home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / exec31.zip / SPAWN.ASM < prev    next >
Assembly Source File  |  1991-08-19  |  82KB  |  3,237 lines

  1. ;
  2. ;    --- Version 3.1 91-08-19 17:48 ---
  3. ;
  4. ;    SPAWN.ASM - Main function for memory swapping spawn call.
  5. ;
  6. ;    Public Domain Software written by
  7. ;        Thomas Wagner
  8. ;        Ferrari electronic GmbH
  9. ;        Beusselstrasse 27
  10. ;        D-1000 Berlin 21
  11. ;        Germany
  12. ;
  13. ;>e
  14. ; Assemble with
  15. ;
  16. ; tasm  /DPASCAL spawn,spawnp          - Turbo Pascal (Tasm only), near
  17. ; tasm  /DPASCAL /DFARCALL spawn,spawnp    - Turbo Pascal (Tasm only), far
  18. ; ?asm  spawn;                  - C, default model (small)
  19. ; ?asm  /DMODL=large spawn          - C, large model
  20. ;
  21. ;    NOTE:    For C, change the 'model' directive below according to your
  22. ;        memory model, or define MODL=xxx on the command line.
  23. ;
  24. ;        For Turbo C Huge model, you must give /DTC_HUGE on the
  25. ;        command line, or define it here.
  26. ;
  27. ;
  28. ; Main function:
  29. ;
  30. ;   PASCAL:
  31. ;       function do_spawn (swapping: integer; 
  32. ;                  execfname: string;
  33. ;               cmdtail: string; 
  34. ;                  envlen: word; 
  35. ;               var envp;
  36. ;               stdin: string; 
  37. ;                   stdout: string;
  38. ;               stderr: string): integer;    
  39. ;
  40. ;   C:
  41. ;       int do_spawn (int swapping,
  42. ;              char *execfname, 
  43. ;              char *cmdtail,
  44. ;              unsigned envlen, 
  45. ;              char *envp,
  46. ;              char *stdin,
  47. ;              char *stdout,
  48. ;              char *stderr)
  49. ;
  50. ;   Parameters:
  51. ;
  52. ;    swapping - swap/spawn/exec function:
  53. ;            < 0: Exec, don't swap
  54. ;                0: Spawn, don't swap
  55. ;            > 0: Spawn, swap
  56. ;                 in this case, prep_swap must have 
  57. ;                 been called beforehand (see below).
  58. ;
  59. ;    cmdtail - command tail for EXEC.
  60. ;
  61. ;    execfname - name and path of file to execute.
  62. ;
  63. ;    envlen - length of environment copy (may be 0).
  64. ;
  65. ;    envp -  pointer to environment block (must be aligned on
  66. ;        paragraph boundary). Unused if envlen is 0.
  67. ;
  68. ;    'cmdtail' and 'execfname' must be zero terminated, even when
  69. ;    calling from Pascal. For Pascal, the length byte of the string
  70. ;    is ignored.
  71. ;
  72. ;   Returns:
  73. ;    0000..00ff:    Returncode of EXECed program
  74. ;    03xx:        DOS-Error xx calling EXEC
  75. ;    0500:        Swapping requested, but prep_swap has not 
  76. ;            been called or returned an error
  77. ;    0501:        MCBs don't match expected setup
  78. ;    0502:        Error while swapping out
  79. ;    06xx:        DOS-Error xx on redirection
  80. ;
  81. ;
  82. ; For swapping, the swap method must be prepared before calling do_spawn.
  83. ;
  84. ;   PASCAL:
  85. ;    function prep_swap (method: word; swapfname: string): integer;
  86. ;   C:
  87. ;    int prep_swap (unsigned method, char *swapfname)
  88. ;
  89. ;   Parameters:
  90. ;
  91. ;    method    - bit-map of allowed swap devices:
  92. ;            01 - Allow EMS
  93. ;            02 - Allow XMS
  94. ;            04 - Allow File swap
  95. ;            10 - Try XMS first, then EMS
  96. ;            40 - Create file as "hidden"
  97. ;            80 - Use "create temp" call for file swap
  98. ;               100 - Don't preallocate file
  99. ;               200 - Check for Network, don't preallocate if net
  100. ;              4000 - Environment block will not be swapped
  101. ;
  102. ;    swapfname - swap file name (may be undefined if the
  103. ;            "method" parameters disallows file swap).
  104. ;            The string must be zero terminated, even
  105. ;            when calling from Pascal. For Pascal, the 
  106. ;            length byte of the string is ignored.
  107. ;
  108. ;   Returns:
  109. ;
  110. ;       A positive integer on success:
  111. ;        1 - EMS swap initialized
  112. ;        2 - XMS swap initialized
  113. ;        4 - File swap initialized
  114. ;    A negative integer on failure:
  115. ;        -1 - Couldn't allocate swap space
  116. ;        -2 - The spawn module is located too low in memory
  117. ;<
  118. ;>d
  119. ; Assemblierung mit
  120. ;
  121. ; tasm  /DPASCAL spawn,spawnp          - Turbo Pascal (nur Tasm), near
  122. ; tasm  /DPASCAL /DFARCALL spawn,spawnp    - Turbo Pascal (nur Tasm), far
  123. ; ?asm  spawn;                  - C, default model (small)
  124. ; ?asm  /DMODL=large spawn          - C, large model
  125. ;
  126. ;    HINWEIS: Für C können Sie entweder die folgende 'model'-Direktive
  127. ;        Ihrem Speichermodell entsprechend ändern, oder beim
  128. ;        Assemblieren MODL=xxx in der Kommandozeile definieren.
  129. ;
  130. ;        Für Turbo C Huge model müssen Sie /DTC_HUGE beim Assemblieren
  131. ;        angeben, oder das Symbol in dieser Quelle definieren.
  132. ;
  133. ;
  134. ; Haupfunktion:
  135. ;
  136. ;   PASCAL:
  137. ;       function do_spawn (swapping: integer; 
  138. ;                  execfname: string;
  139. ;               cmdtail: string; 
  140. ;                  envlen: word; 
  141. ;               var envp)
  142. ;
  143. ;   C:
  144. ;       int do_spawn (int swapping,
  145. ;              char *execfname, 
  146. ;              char *cmdtail,
  147. ;              unsigned envlen, 
  148. ;              char *envp)
  149. ;
  150. ;   Parameter:
  151. ;
  152. ;    swapping - swap/spawn/exec Funktion:
  153. ;            < 0: Exec, kein Auslagern, keine Rückkehr
  154. ;                0: Spawn, kein Auslagern
  155. ;            > 0: Spawn, Auslagern
  156. ;                 in diesem Fall muß vor Aufruf die Funktion
  157. ;                 prep_swap aufgerufen worden sein (siehe unten).
  158. ;
  159. ;    cmdtail - Parameter für das aufgerufene Programm.
  160. ;
  161. ;    execfname - Name und Pfad des auszuführenden Programms.
  162. ;
  163. ;    envlen - Länge der Umgebungsvariablen-Kopie (kann 0 sein).
  164. ;
  165. ;    envp -  Zeiger auf Umgebungsvariablen-Block (muß auf Paragraph-
  166. ;        Grenze adjustiert sein). Wird nicht benutzt wenn der
  167. ;        envlen Parameter 0 ist.
  168. ;
  169. ;    'cmdtail' und 'execfname' müssen 0-Terminiert sein, selbst wenn
  170. ;    der Aufruf von Pascal erfolgt. Bei Aufruf von Pascal wird das
  171. ;    Längenbyte am Anfang des Strings ignoriert.
  172. ;
  173. ;   Liefert:
  174. ;
  175. ;    0000..00ff:    Returncode des ausgeführten Programms
  176. ;    03xx:        DOS-Fehler xx beim Aufruf von EXEC
  177. ;    0500:        Auslagern angefordert, aber prep_swap wurde
  178. ;            nicht aufgerufen oder nicht erfolgreich ausgeführt
  179. ;    0501:        MCBs sind fehlerhaft bzw. verändert
  180. ;    0502:        Fehler bei Auslagerung
  181. ;    06xx:        DOS-Fehler xx bei Redirection
  182. ;
  183. ;
  184. ; Um Auslagern zu können, muß die Auslagerungs-Methode vor Aufruf von
  185. ; do_spawn vorbereitet werden.
  186. ;
  187. ;   PASCAL:
  188. ;    function prep_swap (method: byte; swapfname: string): integer;
  189. ;   C:
  190. ;    int prep_swap (unsigned char method, char *swapfname)
  191. ;
  192. ;   Parameter:
  193. ;
  194. ;    method    - Bit-Map der zulässigen Auslagerungsziele und Optionen:
  195. ;            01 - EMS zulassen
  196. ;            02 - XMS zulassen
  197. ;            04 - Datei zulassen
  198. ;            10 - Erst XMS, dann EMS versuchen
  199. ;            40 - Datei "hidden" erzeugen
  200. ;            80 - "create temp" Funktion bei Datei-Auslagerung
  201. ;               100 - Datei nicht präallozieren
  202. ;               200 - Netzwerk prüfen, nicht präallozieren wenn Netz
  203. ;              4000 - Environmentblock nicht auslagern
  204. ;
  205. ;    swapfname - Auslagerungsdateiname bzw. Pfad (kann undefiniert
  206. ;            sein wenn der "Method" Parameter keine Dateiauslagerung
  207. ;            zulässt).
  208. ;            Der String muß 0-Terminiert sein, selbst wenn
  209. ;            der Aufruf von Pascal erfolgt. Bei Aufruf von Pascal 
  210. ;            wird das Längenbyte am Anfang des Strings ignoriert.
  211. ;
  212. ;   Liefert:
  213. ;
  214. ;       Einen positiven Wert bei Erfolg:
  215. ;        1 - EMS Auslagerung initialisiert
  216. ;        2 - XMS Auslagerung initialisiert
  217. ;        4 - Datei-Auslagerung initialisiert
  218. ;    Einen negativen Wert bei Fehler:
  219. ;        -1 - Kein Platz für Auslagerung
  220. ;        -2 - Das "spawn"-Modul ist zu nah am Beginn des Programms
  221. ;<
  222. ;
  223.     IFDEF    PASCAL
  224.     .model    tpascal
  225.     IFDEF    FARCALL
  226.     %out    Pascal, far calls
  227.     ELSE
  228.     %out    Pascal, near calls
  229.     ENDIF
  230. ;
  231.     extrn    prefixseg: word
  232. ;
  233. ptrsize    =    1
  234.     ELSE
  235.     IFNDEF    MODL
  236.     .model    small,c
  237.     %out    small model
  238.     ELSE
  239. %    .model    MODL,c
  240. %    %out    MODL model
  241.     ENDIF
  242. ;
  243. ptrsize    =    @DataSize
  244. ;
  245.     extrn    _psp: word
  246.     ENDIF
  247. ;
  248.     public    do_spawn
  249.     public    prep_swap
  250. ;
  251. ;>e
  252. ;    Set NO_INHERIT to 0 if you don't want do_exec to mess with
  253. ;    the handle table in the PSP, and/or you do want the child process
  254. ;    to inherit all open files.
  255. ;    If NO_INHERIT is non-0, only the first five handles (the standard
  256. ;    ones) will be inherited, all others will be hidden. This allows
  257. ;    the child to open more files, and also protects you from the child
  258. ;    messing with any open handles.
  259. ;
  260. ;    Set REDIRECT to 0 if you do not want do_spawn to support redirection.
  261. ;<
  262. ;>d
  263. ;    Setzen Sie NO_INHERIT auf 0 wenn Sie nicht wollen, daß do_spawn
  264. ;    die Handle-Tabelle im PSP modifiziert, und/oder der Kindprozess
  265. ;    alle offenen Dateien erben soll.
  266. ;    Wenn NO_INHERIT nicht 0 ist, werden nur die ersten fünf Handles
  267. ;    (die Standard-Handles) vererbt, alle anderen werden versteckt.
  268. ;    Dies erlaubt dem Kindprozess, mehr Dateien zu öffnen, und schützt
  269. ;    Sie außerdem vor Änderungen an offenen Dateien.
  270. ;
  271. ;    Setzen Sie REDIRECT auf 0 wenn do_spawn keine Dateiumleitung 
  272. ;    unterstützen soll.
  273. ;<
  274. ;
  275. NO_INHERIT    =    1
  276. REDIRECT    =    1
  277. ;
  278. ;
  279. stacklen    =    256        ;e local stack
  280.                     ;d Lokaler Stack
  281. ;
  282. ;e    "ems_size" is the EMS block size: 16k.
  283. ;d    "ems_size" ist die EMS-Blockgröße: 16k.
  284. ;
  285. ems_size    =    16 * 1024    ;e EMS block size
  286.                     ;d EMS-Seiten-Größe
  287. ems_parasize    =    ems_size / 16    ;e same in paragraphs
  288.                     ;d desgleichen in Paragraphen
  289. ems_shift    =    10        ;e shift factor for paragraphs
  290.                     ;d Schiebefaktor für Paragraphen
  291. ems_paramask    =    ems_parasize-1    ;e block mask
  292.                     ;d Maske für Paragraphen
  293. ;
  294. ;e    "xms_size" is the unit of measurement for XMS: 1k
  295. ;d    "xms_size" ist die Blockgröße für XMS: 1k
  296. ;
  297. xms_size    =    1024        ;e XMS block size
  298.                     ;d XMS-Block-Größe
  299. xms_parasize    =    xms_size / 16    ;e same in paragraphs
  300.                     ;d desgleichen in Paragraphen
  301. xms_shift    =    6        ;e shift factor for paragraphs
  302.                     ;d Schiebefaktor für Paragraphen
  303. xms_paramask    =    xms_parasize-1    ;e block mask
  304.                     ;d Maske für Paragraphen
  305. ;
  306. ;e    Method flags
  307. ;d    Auslagerungsmethoden-Flags
  308. ;
  309. USE_EMS        =    01h
  310. USE_XMS        =    02h
  311. USE_FILE    =    04h
  312. XMS_FIRST    =    10h
  313. HIDE_FILE    =    40h
  314. CREAT_TEMP    =    80h
  315. NO_PREALLOC    =    100h
  316. CHECK_NET    =    200h
  317. DONT_SWAP_ENV    =    4000h
  318. ;
  319. ;e    Return codes
  320. ;d    Resultatcodes
  321. ;
  322. RC_TOOLOW    =    0102h
  323. RC_BADPREP    =    0500h
  324. RC_MCBERROR    =    0501h
  325. RC_SWAPERROR    =    0502h
  326. RC_REDIRFAIL    =    0600h
  327. ;
  328. EMM_INT        =    67h
  329. ;
  330. ;e    The EXEC function parameter block
  331. ;d    Der Parameterblock für die EXEC-Funktion
  332. ;
  333. exec_block    struc
  334. envseg    dw    ?        ;e environment segment
  335.                 ;d Segmentadresse Umgebungsvariablenblock
  336. ppar    dw    ?        ;e program parameter string offset
  337.                 ;d Programmparameterstring Offset
  338. pparseg    dw    ?        ;e program parameter string segment
  339.                 ;d Programmparameterstring Segment
  340. fcb1    dw    ?        ; FCB offset
  341. fcb1seg    dw    ?        ; FCB segment
  342. fcb2    dw    ?        ; FCB offset
  343. fcb2seg    dw    ?        ; FCB segment
  344. exec_block    ends
  345. ;
  346. ;e    Structure of an XMS move control block
  347. ;d    Struktur eines XMS move Kontrollblocks
  348. ;
  349. xms_control    struc
  350. lenlo        dw    ?    ;e length to move (doubleword)
  351.                 ;d Länge für Move (Doppelwort)
  352. lenhi        dw    ?
  353. srchnd        dw    ?    ;e source handle (0 for standard memory)
  354.                 ;d Quell-Handle (0 für Standardspeicher)
  355. srclo        dw    ?    ;e source address (doubleword or seg:off)
  356.                 ;d Quell-Adresse (Doppelwort oder seg:off)
  357. srchi        dw    ?
  358. desthnd        dw    ?    ;e destination handle (0 for standard memory)
  359.                 ;d Ziel-Handle (0 für Standardspeicher)
  360. destlo        dw    ?    ;e destination address (doubleword or seg:off)
  361.                 ;d Ziel-Adresse (Doppelwort oder seg:off)
  362. desthi        dw    ?
  363. xms_control    ends
  364. ;
  365. ;e    The structure of the start of an MCB (memory control block)
  366. ;d    Die Struktur des Beginns eines MCB (Speicher-Kontrollblock)
  367. ;
  368. mcb        struc
  369. id        db    ?
  370. owner        dw    ?
  371. paras        dw    ?
  372. mcb        ends
  373. ;>e
  374. ;    The structure of an internal MCB descriptor.
  375. ;    CAUTION: This structure is assumed to be no larger than 16 bytes
  376. ;    in several places in the code, and to be exactly 16 bytes when
  377. ;    swapping in from file. Be careful when changing this structure.
  378. ;<
  379. ;>d
  380. ;    Die Struktur eines internen MCB-Descriptors.
  381. ;    ACHTUNG: An mehreren Stellen im Code wird angenommen, daß die
  382. ;    Länge dieser Struktur 16 Bytes nicht überschreitet. Beim
  383. ;    Zurücklesen von Datei wird angenommen, daß die Länge exakt 16
  384. ;    Bytes beträgt. Bei Änderungen in dieser Struktur ist daher
  385. ;    Vorsicht geboten.
  386. ;<
  387. mcbdesc        struc
  388. addr        dw    ?    ;e paragraph address of the MCB
  389.                 ;d Paragraph-Adresse des MCB
  390. msize        dw    ?    ;e size in paragraphs (excluding header)
  391.                 ;d Größe in Paragraphen (Ausschließlich Header)
  392. swoffset    dw    ?    ;e swap offset (0 in all blocks except first)
  393.                 ;d Auslagerungs-Offset (0 in allen Blöcken 
  394.                 ;d außer dem ersten)
  395. swsize        dw    ?    ;e swap size (= msize + 1 except in first)
  396.                 ;d Auslagerungsgröße (= msize + 1 außer
  397.                 ;d im ersten Block)
  398. num_follow    dw    ?    ;e number of following MCBs
  399.                 ;d Zahl der folgenden MCBs
  400.         dw    3 dup(?) ;e pad to paragraph (16 bytes)
  401.                  ;d Auffüllen auf Paragraphen (16 Bytes)
  402. mcbdesc        ends
  403. ;
  404. ;e    The variable block set up by prep_swap
  405. ;d    Der Variablenblock der durch prep_swap initialisiert wird
  406. ;
  407. prep_block    struc
  408. xmm        dd    ?        ;e XMM entry address
  409.                     ;d Einsprungadresse XMM
  410. first_mcb    dw    ?        ;e Segment of first MCB
  411.                     ;d Segment des ersten MCB
  412. psp_mcb        dw    ?        ;e Segment of MCB of our PSP
  413.                     ;d Segment des MCB unseres PSP
  414. env_mcb        dw    ?        ;e MCB of Environment segment
  415.                     ;d MCB des Umgebungsvariablenblocks
  416. noswap_mcb    dw    ?        ;e MCB that may not be swapped
  417.                     ;d MCB der nicht Ausgelagert wird
  418. ems_pageframe    dw    ?        ;e EMS page frame address
  419.                     ;d EMS-Seiten-Adresse
  420. handle        dw    ?        ;e EMS/XMS/File handle
  421.                     ;d Handle für EMS/XMS/Datei
  422. total_mcbs    dw    ?        ;e Total number of MCBs
  423.                     ;d Gesamtzahl MCBs
  424. swapmethod    db    ?        ;e Method for swapping
  425.                     ;d Auslagerungsmethode
  426. swapfilename    db    81 dup(?)    ;e Swap file name if swapping to file
  427.                     ;d Auslagerungsdateiname
  428. prep_block    ends
  429. ;
  430. ;----------------------------------------------------------------------
  431. ;>e
  432. ;    Since we'll be moving code and data around in memory,
  433. ;    we can't address locations in the resident block with
  434. ;    normal address expressions. MASM does not support
  435. ;    defining variables with a fixed offset, so we have to resort
  436. ;    to a kludge, and define the shrunk-down code as a structure.
  437. ;    It would also be possible to use an absolute segment for the
  438. ;    definition, but this is not supported by the Turbo Pascal linker.
  439. ;
  440. ;    All references to low-core variables from low-core itself 
  441. ;    are made through DS, so we define a text macro "lmem" that 
  442. ;    expands to "ds:". When setting up low core from the normal
  443. ;    code, ES is used to address low memory, so this can't be used.
  444. ;<
  445. ;>d
  446. ;    Da Code und Daten in andere Speicherbereiche kopiert werden,
  447. ;    können Adressen im residenten Teil nicht mit normalen Adress-
  448. ;    ausdrücken angesprochen werden. MASM unterstützt leider nicht
  449. ;    die Definition von Variablen mit festen Offsets, sodaß wir
  450. ;    den residenten Teil als Struktur definieren müssen. Eine Definition
  451. ;    als absolutes Segment wäre zwar in MASM möglich, dies wird jedoch
  452. ;    vom Turbo Pascal Linker nicht unterstützt.
  453. ;
  454. ;    Alle Referenzen auf Variablen im residenten Teil von diesem
  455. ;    Teil selbst geschehen über DS, hierfür kann daher ein Text-Makro
  456. ;    "lmem" definiert werden, das zu "ds:" expandiert wird. Beim
  457. ;    Aufsetzen des residenten Teils vom normalen Programm geschieht
  458. ;    die Adressierung über ES, sodaß dieses Makro dort nicht verwendet
  459. ;    werden darf.
  460. ;<
  461. lmem    equ    <ds:>
  462. ;>e
  463. ;    The memory structure for the shrunk-down code, excluding the
  464. ;    code itself. The code follows this block.
  465. ;<
  466. ;>d
  467. ;    Die Struktur des residenten Teils, ausschließlich des Programm-
  468. ;    Codes. Der Programmcode folgt diesem Block.
  469. ;<
  470. parseg        struc
  471.         db    18h dup(?)
  472. psp_handletab    db    20 dup(?)
  473. psp_envptr    dw    ?
  474.         dd    ?
  475. psp_handlenum    dw    ?
  476. psp_handleptro    dw    ?
  477. psp_handleptrs    dw    ?
  478.         db    5ch-38h dup(?)    ;e start after PSP
  479.                     ;d Start nach PSP
  480. ;
  481. save_ss        dw    ?        ;e 5C - saved global ss
  482.                     ;d 5C - Sicherung globales SS
  483. save_sp        dw    ?        ;e 5E - saved global sp
  484.                     ;d 5E - Sicherung globaler SP
  485. xfcb1        db    16 dup(?)    ;e 60..6F - default FCB
  486.                     ;d 60..6F - Standard-FCB
  487. xfcb2        db    16 dup(?)    ;e 70..7F - default FCB
  488.                     ;d 70..7f - Standard-FCB
  489. zero        dw    ?        ;e 80 Zero command tail length (dummy)
  490.                     ;d 80 Null-Kommandozeile (Dummy)
  491. ;
  492. expar        db    TYPE exec_block dup (?) ; exec-parameter-block
  493. spx        dw    ?        ;e saved local sp
  494.                     ;d Sicherung lokaler SP
  495. div0_off    dw    ?        ;e divide by zero vector save
  496.                     ;d Sicherung divide-by-zero Vektor
  497. div0_seg    dw    ?
  498.         IF    NO_INHERIT
  499. lhandlesave    db    26 dup(?)    ;e saved handle table and pointer
  500.                     ;d Sicherung Handle-Tabelle und Pointer
  501.         IF    REDIRECT
  502. lredirsav    db    6 dup(?)    ;e saved redirection handles
  503.                     ;d Sicherung Umleitungs-Handles
  504.         ENDIF
  505.         ENDIF
  506.         IF    REDIRECT
  507. lstdinsav    dw    3 dup(?)    ;e duped redirection handles
  508.                     ;d Umleitungs-Handles aus 'dup'
  509.         ENDIF
  510. filename    db    82 dup(?)    ;e exec filename
  511.                     ;d EXEC-Dateiname
  512. progpars    db    128 dup(?)    ;e command tail
  513.                     ;d Kommandozeile
  514.         db    stacklen dup(?)    ;e local stack space
  515.                     ;d Lokaler Stackbereich
  516. mystack        db    ?
  517. lprep        db    TYPE prep_block dup(?)    ;e the swapping variables
  518.                         ;d die Auslagerungsvariablen
  519. lcurrdesc    db    TYPE mcbdesc dup(?)    ;e the current MCB descriptor
  520.                         ;d Descriptor aktueller MCB
  521. lxmsctl        db    TYPE xms_control dup(?)
  522. eretcode    dw    ?        ;e EXEC return code
  523.                     ;d Resultatcode EXEC
  524. retflags    dw    ?        ;e EXEC return flags
  525.                     ;d Resultatflags EXEC
  526. cgetmcb        dw    ?        ;e address of get_mcb
  527.                     ;d Adresse von get_mcb
  528. ;
  529. parseg    ends
  530. ;
  531. param_len    =    ((TYPE parseg + 1) / 2) * 2    ; make even
  532. codebeg        =    param_len
  533. ;
  534.     .code
  535. ;
  536. ;------------------------------------------------------------------------
  537. ;
  538. lowcode_begin:
  539. ;>e
  540. ;       The following parts of the program code will be moved to
  541. ;    low core and executed there, so there must be no absolute 
  542. ;    memory references.
  543. ;    The call to get_mcb must be made indirect, since the offset
  544. ;    from the swap-in routine to get_mcb will not be the same
  545. ;    after moving.
  546. ;
  547. ;
  548. ;    get_mcb allocates a block of memory by modifying the MCB chain
  549. ;    directly.
  550. ;
  551. ;    On entry, lcurrdesc has the mcb descriptor for the block to
  552. ;          allocate.
  553. ;
  554. ;    On exit,  Carry is set if the block couldn't be allocated.
  555. ;
  556. ;    Uses     AX, BX, CX, ES
  557. ;    Modifies lprep.first_mcb
  558. ;<
  559. ;>d
  560. ;       Der folgende Teil des Programm-Codes wird in den unteren Speicher-
  561. ;    bereich kopiert und dort ausgeführt, es dürfen daher keine
  562. ;    absoluten Speicheradressen verwendet werden.
  563. ;    Der Aufruf von get_mcb muß indirekt erfolgen, da der Offset
  564. ;    der Einlagerungs-Routine zu get_mcb nach dem Kopieren nicht
  565. ;    mehr mit der Definition übereinstimmt.
  566. ;
  567. ;
  568. ;    get_mcb alloziert einen Speicherblock durch direkte Modifikation
  569. ;        der MCB-Kette.
  570. ;
  571. ;    Bei Einsprung enthält lcurrdesc den Deskriptor für den zu
  572. ;        allozierenden Block.
  573. ;
  574. ;    Bei Rückkehr ist das Carry-Flag gesetzt wenn der Block nicht
  575. ;        alloziert werden konnte.
  576. ;
  577. ;    Benutzt    AX, BX, CX, ES
  578. ;    Modifiziert lprep.first_mcb
  579. ;<
  580. get_mcb    proc    near
  581. ;
  582.     mov    ax,lmem lprep.first_mcb
  583.     mov    bx,lmem lcurrdesc.addr
  584. ;
  585. getmcb_loop:
  586.     mov    es,ax
  587.     cmp    ax,bx
  588.     ja    gmcb_abort        ;e halt if MCB > wanted
  589.                     ;d Abbrechen wenn MCB > gewünschtem
  590.     je    mcb_found        ;e jump if same addr as wanted
  591.                     ;d jump wenn Adresse gleich gewünschter
  592.     add    ax,es:paras        ;e last addr
  593.                     ;d Letze Adresse
  594.     inc    ax            ; next mcb
  595.     cmp    ax,bx
  596.     jbe    getmcb_loop        ;e Loop if next <= wanted
  597.                     ;d Nochmal wenn nächster <= gewünschter
  598. ;
  599. ;>e
  600. ;    The wanted MCB starts within the current MCB. We now have to
  601. ;    create a new MCB at the wanted position, which is initially
  602. ;    free, and shorten the current MCB to reflect the reduced size.
  603. ;<
  604. ;>d
  605. ;    Der gewünschte MCB beginnt innerhalb des laufenden MCB. Es muß
  606. ;    nun ein MCB an der gewünschten Position eingerichtet werden, und
  607. ;    der laufende MCB ist zu kürzen.
  608. ;<
  609.     cmp    es:owner,0
  610.     jne    gmcb_abort        ;e halt if not free
  611.                     ;d Abbruch wenn nicht frei
  612.     mov    bx,es            ;e current
  613.                     ;d laufender
  614.     inc    bx            ;e + 1 (header doesn't count)
  615.                     ;d + 1 (Header zählt nicht)
  616.     mov    ax,lmem lcurrdesc.addr
  617.     sub    ax,bx            ;e paragraphs between MCB and wanted
  618.                     ;d Paragraphen zwischen MCB 
  619.                     ;d und gewünschtem
  620.     mov    bx,es:paras        ;e paras in current MCB
  621.                     ;d Paragraphen in laufendem MCB
  622.     sub    bx,ax            ;e remaining paras
  623.                     ;d Restliche Paragraphen
  624.     dec    bx            ;e -1 for header
  625.                     ;d -1 für Header
  626.     mov    es:paras,ax        ;e set new size for current
  627.                     ;d neue Größe für laufenden Setzen
  628.     mov    cl,es:id        ;e old id
  629.                     ;d Alte ID
  630.     mov    es:id,4dh        ;e set id: there is a next
  631.                     ;d Setze ID: es gibt einen nächsten
  632.     mov    ax,lmem lcurrdesc.addr
  633.     mov    es,ax
  634.     mov    es:id,cl        ;e and init to free
  635.                     ;d und initialisiere auf Frei
  636.     mov    es:owner,0
  637.     mov    es:paras,bx
  638. ;>e
  639. ;    We have found an MCB at the right address. If it's not free,
  640. ;    abort. Else check the size. If the size is ok, we're done 
  641. ;    (more or less).
  642. ;<
  643. ;>d
  644. ;    Wir haben einen MCB an der korrekten Adresse. Falls er nicht
  645. ;    frei ist, abbrechen. Sonst Größe prüfen. Falls die Größe
  646. ;    korrekt ist, sind wir (mehr oder weniger) fertig.
  647. ;<
  648. mcb_found:
  649.     mov    es,ax
  650.     cmp    es:owner,0
  651.     je    mcb_check        ;e continue if free
  652.                     ;d weiter wenn Frei
  653. ;
  654. gmcb_abort:
  655.     stc
  656.     ret
  657. ;
  658. mcb_check:
  659.     mov    ax,es:paras        ;e size
  660.                     ;d Größe
  661.     cmp    ax,lmem lcurrdesc.msize    ;e needed size
  662.                     ;d gewünschte Größe
  663.     jae    mcb_ok            ;e ok if enough space
  664.                     ;d OK wenn genug Platz
  665. ;>e
  666. ;    If there's not enough room in this MCB, check if the next
  667. ;    MCB is free, too. If so, coalesce both MCB's and check again.
  668. ;<
  669. ;>d
  670. ;    Wenn in diesem MCB nicht genug Platz ist, den nächsten MCB
  671. ;    prüfen ob er ebenfalls frei ist. Falls ja, beide Blöcke
  672. ;    kombinieren und nochmals prüfen.
  673. ;<
  674.     cmp    es:id,4dh
  675.     jnz    gmcb_abort        ;e halt if no next
  676.                     ;d Abbruch wenn kein nächster
  677.     push    es            ;e save current
  678.                     ;d Laufenden sichern
  679.     mov    bx,es
  680.     add    ax,bx
  681.     inc    ax            ;e next MCB
  682.                     ;d nächter MCB
  683.     mov    es,ax
  684.     cmp    es:owner,0        ;e next free ?
  685.                     ;d ist der nächste frei?
  686.     jne    gmcb_abort        ;e halt if not
  687.                     ;d Abbruch wenn nein
  688.     mov    ax,es:paras        ;e else load size
  689.                     ;d sonst Größe laden
  690.     inc    ax            ;e + 1 for header
  691.                     ;d + 1 für Header
  692.     mov    cl,es:id        ;e and load ID
  693.                     ;d und ID laden
  694.     pop    es            ;e back to last MCB
  695.                     ;d zurück zum letzten MCB
  696.     add    es:paras,ax        ;e increase size
  697.                     ;d Größe erhöhen
  698.     mov    es:id,cl        ;e and store ID
  699.                     ;d und ID abspeichern
  700.     jmp    mcb_check        ;e now try again
  701.                     ;d nochmal versuchen
  702. ;>e
  703. ;    The MCB is free and large enough. If it's larger than the
  704. ;    wanted size, create another MCB after the wanted.
  705. ;<
  706. ;>d
  707. ;    Der MCB ist frei und groß genug. Wenn er größer als die gewünschte
  708. ;    Größe ist, muß ein weiterer MCB nach dem gewünschten erzeugt werden.
  709. ;<
  710. mcb_ok:
  711.     mov    bx,es:paras
  712.     sub    bx,lmem lcurrdesc.msize
  713.     jz    mcb_no_next        ;e ok, no next to create
  714.                     ;d OK, kein neuer einzurichten
  715.     push    es
  716.     dec    bx            ;e size of next block
  717.                     ;d Größe des nächsten Blocks
  718.     mov    ax,es
  719.     add    ax,lmem lcurrdesc.msize
  720.     inc    ax            ;e next MCB addr
  721.                     ;d Adresse des nächsten MCB
  722.     mov    cl,es:id        ;e id of this block
  723.                     ;d ID dieses Blocks
  724.     mov    es,ax            ;e address next
  725.                     ;d nächsten adressieren
  726.     mov    es:id,cl        ;e store id
  727.                     ;d ID abspeichern
  728.     mov    es:paras,bx        ;e store size
  729.                     ;d Größe abspeichern
  730.     mov    es:owner,0        ;e and mark as free
  731.                     ;d und als frei markieren
  732.     pop    es            ;e back to old MCB
  733.                     ;d zurück zum alten MCB
  734.     mov    es:id,4dh        ;e mark next block present
  735.                     ;d markieren daß weiterer existiert
  736.     mov    ax,lmem lcurrdesc.msize    ;e and set size to wanted
  737.                     ;d und Größe auf gewünschte setzen
  738.     mov    es:paras,ax
  739. ;
  740. mcb_no_next:
  741.     mov    es:owner,cx        ;e set owner to current PSP
  742.                     ;d owner auf laufenden PSP setzen
  743. ;>e
  744. ;    Set the 'first_mcb' pointer to the current one, so we don't
  745. ;    walk through all the previous blocks the next time.
  746. ;    Also, check if the block we just allocated is the environment
  747. ;    segment of the program. If so, restore the environment pointer
  748. ;    in the PSP.
  749. ;<
  750. ;>d
  751. ;    Der 'first_mcb'-Pointer wird auf den aktuellen gesetzt,
  752. ;    damit beim nächsten Mal nicht wieder alle vorangegangenen
  753. ;    Blöcke abgelatscht werden müssen.
  754. ;    Außerdem wird der gerade allozierte Block geprüft, ob es der
  755. ;    Umgebungsvariablenblock des Programms ist. Wenn ja, wird der
  756. ;    entsprechende Pointer im PSP wiederhergestellt.
  757. ;<
  758.     mov    ax,es
  759.     mov    lmem lprep.first_mcb,ax
  760.     cmp    lmem lprep.env_mcb,ax
  761.     jne    getmcb_finis
  762.     inc    ax
  763.     mov    lmem psp_envptr,ax
  764. ;
  765. getmcb_finis:
  766.     clc
  767.     ret                ;e all finished (whew!)
  768.                     ;d endlich geschafft
  769. ;
  770. get_mcb    endp
  771. ;
  772. ;
  773. ireti:
  774.     iret
  775. ;
  776. ;>e
  777. ;    The actual EXEC call.
  778. ;    Registers on entry:
  779. ;        BX    = paragraphs to keep (0 if no swap)
  780. ;        CX     = length of environment to copy (words) or zero
  781. ;        DS:SI    = environment source
  782. ;        ES:DI    = environment destination
  783. ;        (ES = our low core code segment)
  784. ;
  785. ;
  786. ;    copy environment buffer down if present
  787. ;<
  788. ;>d
  789. ;    Der eigentliche EXEC Aufruf.
  790. ;    Register bei Einsprung:
  791. ;        BX    = Residente Paragraphen (0 wenn keine Auslagerung)
  792. ;        CX     = Länge des Umgebungsvariablenblocks in Worten oder 0
  793. ;        DS:SI    = Quelladresse Umgebungsvariablenblock
  794. ;        ES:DI    = Zieladresse Umgebungsvariablenblock
  795. ;        (ES = Adresse residenter Teil)
  796. ;
  797. ;
  798. ;    Umgebungsvariablenblock nach unten kopieren wenn vorhanden
  799. ;<
  800. doexec:
  801.     jcxz    noenvcpy
  802.     rep movsw
  803. ;
  804. noenvcpy:
  805.     push    es            ; DS = ES = low core = PSP
  806.     pop    ds
  807.     or    bx,bx
  808.     jz    no_shrink
  809. ;
  810. ;e    first, shrink the base memory block down.
  811. ;d    Zuerst den Basisblock reduzieren.
  812. ;
  813.         mov    ah,04ah
  814.     int     21h                     ; resize memory block
  815. ;>e
  816. ;    Again walk all MCBs. This time, all blocks owned by the 
  817. ;    current process are released.
  818. ;<
  819. ;>d
  820. ;    Wieder mal alle MCBs durchgehen. Diesmal werden alle Blöcke 
  821. ;    die zu diesem Prozeß gehören freigegeben.
  822. ;<
  823.     mov    si,lmem lprep.first_mcb
  824.     or    si,si
  825.     jz    no_shrink
  826.     mov    dx,lmem lprep.psp_mcb
  827.     mov    bx,dx
  828.     inc    bx            ; base PSP (MCB owner)
  829.     mov    di,lmem lprep.noswap_mcb
  830. ;
  831. free_loop:
  832.     cmp    si,dx
  833.     je    free_next        ;e don't free base block
  834.                     ;d Basisblock nicht freigeben
  835.     cmp    si,di
  836.     je    free_next
  837.     mov    es,si
  838.     cmp    bx,es:owner        ;e our process?
  839.                     ;d unser Prozeß?
  840.     jne    free_next        ;e next if not
  841.                     ;d nächsten wenn nein
  842.     cmp    si,lmem lprep.env_mcb    ;e is this the environment block?
  843.                     ;d ist dies der Umgebungsvariablenblock?
  844.     jne    free_noenv
  845.     mov    ds:psp_envptr,0        ;e else clear PSP pointer
  846.                     ;d sonst PSP-pointer löschen
  847. ;
  848. free_noenv:
  849.     inc    si
  850.     mov    es,si
  851.     dec    si
  852.     mov    ah,049h            ;e free memory block
  853.                     ;d Speicher freigeben
  854.     int    21h
  855. ;
  856. free_next:
  857.     mov    es,si
  858.     cmp    es:id,4dh        ;e normal block?
  859.                     ;d Normaler Block?
  860.     jne    free_ready        ;e ready if end of chain
  861.                     ;d Fertig wenn Ende der Kette
  862.     add    si,es:paras        ;e start + length
  863.                     ;d Beginn + Länge
  864.     inc    si            ;e next MCB
  865.                     ;d Nächster MCB
  866.     jmp    free_loop
  867. ;
  868. free_ready:
  869.     mov    ax,ds
  870.     mov    es,ax
  871. ;
  872. no_shrink:
  873.     mov    dx,filename        ;e params for exec
  874.                     ;d Parameter für EXEC
  875.     mov    bx,expar
  876.     mov    ax,04b00h
  877.     int    21h            ; exec
  878. ;>e
  879. ;    Return from EXEC system call. Don't count on any register except
  880. ;    CS to be restored (DOS 2.11 and previous versions killed all regs).
  881. ;<
  882. ;>d
  883. ;    Rückkehr vom EXEC Aufruf. Alle Register außer CS können zerstört
  884. ;    sein (DOS-Versionen 2.11 und früher zerstörten auch SS und SP).
  885. ;<
  886.     mov    bx,cs
  887.     mov    ds,bx
  888.     mov    es,bx
  889.     mov    ss,bx
  890.     mov    sp,lmem spx
  891.     cld
  892.     mov    lmem eretcode,ax    ;e save return code
  893.                     ;d Resultatcode sichern
  894.     pushf
  895.     pop    bx
  896.     mov    lmem retflags,bx    ;e and returned flags
  897.                     ;d und die gelieferten Flags
  898. ;
  899. ;e    Cancel Redirection
  900. ;d    Dateiumleitung aufheben
  901. ;
  902.     IF    REDIRECT
  903.     IF    NO_INHERIT
  904.     mov    si,lredirsav
  905.     mov    di,psp_handletab+5
  906.     mov    cx,3
  907.     rep movsw
  908.     ENDIF
  909.     mov    si,lstdinsav
  910.     xor    cx,cx
  911. ;
  912. lredirclose:
  913.     lodsw
  914.     cmp    ax,-1
  915.     je    lredclosenext
  916.     mov    bx,ax
  917.     mov    ah,46h
  918.     int    21h
  919. ;
  920. lredclosenext:
  921.     inc    cx
  922.     cmp    cx,3
  923.     jb    lredirclose
  924.     ENDIF
  925. ;
  926. ;e    restore handle table and pointer
  927. ;d    Wiederherstellen Handle-Tabelle und Pointer
  928. ;
  929.     IF    NO_INHERIT
  930.     mov    si,lhandlesave
  931.     mov    di,psp_handletab
  932.     mov    cx,10
  933.     rep movsw
  934.     mov    di,psp_handlenum
  935.     movsw
  936.     movsw
  937.     movsw
  938.     ENDIF
  939. ;
  940.     cmp    lmem lprep.swapmethod,0
  941.     je    exec_memok
  942.     jg    exec_expand
  943. ;
  944. ;    Terminate.
  945. ;
  946.     test    lmem retflags,1        ; carry?
  947.     jnz    exec_term        ;e use EXEc retcode if set
  948.                     ;d Resultat von EXEC liefern wenn ja
  949.     mov    ah,4dh            ;e else get program return code
  950.                     ;d Sonst Resultat von Programm holen
  951.     int    21h
  952. ;
  953. exec_term:
  954.     mov    ah,4ch
  955.     int    21h
  956. ;
  957. ;
  958. exec_expand:
  959.     mov    ah,4ah            ; expand memory
  960.     mov    bx,lmem lcurrdesc.msize
  961.     int    21h
  962.     jnc    exec_memok
  963.     mov    ax,4cffh
  964.     int    21h            ;e terminate on error
  965.                     ;d Abbrechen bei Fehler
  966. ;
  967. ;e    Swap memory back
  968. ;d    Zurücklesen Speicher
  969. ;
  970.     nop
  971. ;
  972. exec_memok:
  973. ;
  974. ;e    FALL THROUGH to the appropriate swap-in routine
  975. ;d    Weiter in der passenden Einlagerungsroutine
  976. ;
  977. ;
  978. getmcboff    =    offset get_mcb - offset lowcode_begin
  979. iretoff        =    offset ireti - offset lowcode_begin
  980. doexec_entry    =    offset doexec - offset lowcode_begin
  981. base_length    =    offset $ - offset lowcode_begin
  982. ;
  983. ;-----------------------------------------------------------------------
  984. ;>e
  985. ;    The various swap in routines follow. Only one of the routines
  986. ;    is copied to low memory.
  987. ;    Note that the routines are never actually called, the EXEC return
  988. ;    code falls through. The final RET thus will return to the restored
  989. ;    memory image.
  990. ;
  991. ;    On entry, DS must point to low core.
  992. ;    On exit to the restored code, DS is unchanged.
  993. ;
  994. ;
  995. ;    swapin_ems:    swap in from EMS.
  996. ;<
  997. ;>d
  998. ;    Es folgen die verschiedenen Wiederherstellungsroutinen. Nur 
  999. ;    eine der Routinen wird in den residenten Teil kopiert.
  1000. ;    Beachten Sie, daß die Routinen nicht tatsächlich aufgerufen
  1001. ;    werden, der Code nach dem EXEC-Aufruf läuft in sie hinein. Das
  1002. ;    abschließende RET kehrt daher in das wiederhergestellte Haupt-
  1003. ;    programm zurück.
  1004. ;
  1005. ;    Bei Einsprung zeight DS auf den Basis-PSP.
  1006. ;    Bei Rückkehr in das wiederhergestellte Programm ist DS unverändert.
  1007. ;
  1008. ;
  1009. ;    swapin_ems:    Wiederherstellen von EMS.
  1010. ;<
  1011. swapin_ems    proc    far
  1012. ;
  1013.     xor    bx,bx
  1014.     mov    si,ems_parasize
  1015.     mov    dx,lmem lprep.handle    ; EMS handle
  1016. ;
  1017. swinems_main:
  1018.     push    ds
  1019.     mov    cx,lmem lcurrdesc.swsize    ;e block length in paras
  1020.                         ;d Blocklänge in Paragraphen
  1021.     mov    di,lmem lcurrdesc.swoffset    ;e swap offset
  1022.                         ;d Lese-Offset
  1023.     mov    es,lmem lcurrdesc.addr        ;e segment to swap
  1024.                         ;d Lese-Segment
  1025.     mov    ds,lmem lprep.ems_pageframe    ; page frame address
  1026. ;
  1027.     mov    ax,ems_parasize        ;e max length
  1028.                     ;d Maximale Länge
  1029.     sub    ax,si            ;e minus current offset
  1030.                     ;d Minus laufender Offset
  1031.     jnz    swinems_ok        ;e go copy if nonzero
  1032.                     ;d Kopieren wenn nicht 0
  1033. ;
  1034. swinems_loop:
  1035.     mov    ax,4400h        ;e map in next page
  1036.                     ;d Nächste EMS-Page einmappen
  1037.     int    EMM_INT
  1038.     or    ah,ah
  1039.     jnz    swinems_error
  1040.     mov    si,0            ;e reset offset
  1041.                     ;d Offset zurücksetzen
  1042.     inc    bx            ;e bump up page number
  1043.                     ;d Seitennummer erhöhen
  1044.     mov    ax,ems_parasize        ;e max length to copy
  1045.                     ;d Maximale Länge
  1046. ;
  1047. swinems_ok:
  1048.     cmp    ax,cx            ;e length to copy
  1049.                     ;d zu kopierende Länge
  1050.     jbe    swinems_doit        ;e go do it if <= total length
  1051.                     ;d kopieren wenn <= Gesamtlänge
  1052.     mov    ax,cx            ;e else use total length
  1053.                     ;d sonst Gesamtlänge kopieren
  1054. ;
  1055. swinems_doit:
  1056.     sub    cx,ax            ;e subtract copy length from total
  1057.                     ;d Gesamtlänge -= kopierte Länge
  1058.     push    cx            ;e and save
  1059.                     ;d sichern
  1060.     push    ax            ;e save the copy length in paras
  1061.                     ;d Sichern Kopierlänge in Paragraphen
  1062.     push    si
  1063.     push    di
  1064.     mov    cl,3
  1065.     shl    ax,cl            ;e convert to number of words (!)
  1066.                     ;d Konvertieren in Anzahl Worte (!)
  1067.     inc    cl
  1068.     shl    si,cl            ;e convert to byte address
  1069.                     ;d In Byte-Adresse konvertieren
  1070.     mov    cx,ax
  1071.     rep movsw
  1072.     pop    di
  1073.     pop    si
  1074.     pop    cx            ;e copy length in paras
  1075.                     ;d Kopierlänge in Paragraphen
  1076.     mov    ax,es
  1077.     add    ax,cx            ;e add copy length to dest segment
  1078.                     ;d Kopierlänge auf Zielsegment
  1079.     add    si,cx            ;e and EMS page offset
  1080.                     ;d und EMS-Seiten-Offset addieren
  1081.     mov    es,ax
  1082.     pop    cx            ;e remaining length
  1083.                     ;d Restlänge
  1084.     or    cx,cx            ;e did we copy everything?
  1085.                     ;d Alles kopiert?
  1086.     jnz    swinems_loop        ;e go loop if not
  1087.                     ;d Nochmal wenn nein
  1088. ;
  1089.     pop    ds
  1090.     cmp    lmem lcurrdesc.num_follow,0    ;e another MCB?
  1091.                         ;d noch ein MCB?
  1092.     je    swinems_complete    ;e exit if not
  1093.                     ;d Fertig wenn nein
  1094. ;
  1095. ;e    Another MCB follows, read next mcb descriptor into currdesc
  1096. ;d    Ein weiterer MCB folgt, lesen MCB Deskriptor nach currdesc
  1097. ;
  1098.     cmp    si,ems_parasize
  1099.     jb    swinems_nonewpage    ;e no new block needed
  1100.                     ;d kein neuer Block nötig
  1101.     mov    ax,4400h        ; map page, phys = 0
  1102.     int    EMM_INT
  1103.     or    ah,ah
  1104.     jnz    swinems_error1
  1105.     mov    si,0
  1106.     inc    bx
  1107. ;
  1108. swinems_nonewpage:
  1109.     push    si
  1110.     push    ds
  1111.     mov    ax,ds
  1112.     mov    es,ax
  1113.     mov    ds,lmem lprep.ems_pageframe    ; page frame address
  1114.     mov    cl,4
  1115.     shl    si,cl            ;e convert to byte address
  1116.                     ;d in Byte-Adresse konvertieren
  1117.     mov    cx,TYPE mcbdesc
  1118.     mov    di,lcurrdesc
  1119.     rep movsb
  1120.     pop    ds
  1121.     pop    si
  1122.     inc    si            ;e one paragraph
  1123.                     ;d Einen Paragraphen
  1124. ;
  1125.     push    bx
  1126.     call    lmem cgetmcb
  1127.     pop    bx
  1128.     jc    swinems_error1
  1129.     jmp    swinems_main
  1130. ;
  1131. swinems_complete:
  1132.     mov    ah,45h            ;e release EMS pages
  1133.                     ;d Freigeben EMS-Speicher
  1134.     int    EMM_INT
  1135.     ret
  1136. ;
  1137. swinems_error:
  1138.     pop    ds
  1139. swinems_error1:
  1140.     mov    ah,45h            ;e release EMS pages on error
  1141.                     ;d Bei Fehler EMS freigeben
  1142.     int    EMM_INT
  1143.     mov    ax,4cffh
  1144.     int    21h            ; terminate
  1145. ;
  1146. swapin_ems    endp
  1147. ;
  1148. swinems_length    = offset $ - offset swapin_ems
  1149. ;
  1150. ;
  1151. ;e    swapin_xms:    swap in from XMS.
  1152. ;d    swapin_xms:    Wiederherstellen von XMS.
  1153. ;
  1154. swapin_xms    proc    far
  1155. ;
  1156.     mov    ax,lmem lprep.handle    ; XMS handle
  1157.     mov    lmem lxmsctl.srchnd,ax     ;e source is XMS
  1158.                     ;d Quelle ist XMS
  1159.     mov    lmem lxmsctl.desthnd,0     ;e dest is normal memory
  1160.                     ;d Ziel ist Standardspeicher
  1161.     mov    lmem lxmsctl.srclo,0
  1162.     mov    lmem lxmsctl.srchi,0
  1163. ;
  1164. swinxms_main:
  1165.     mov    ax,lmem lcurrdesc.swsize ;e size in paragraphs
  1166.                      ;d Größe in Paragraphen
  1167.     mov    cl,4
  1168.     rol    ax,cl            ;e size in bytes + high nibble
  1169.                     ;d Größe in Bytes + high nibble
  1170.     mov    dx,ax
  1171.     and    ax,0fff0h        ; low word
  1172.     and    dx,0000fh        ; high word
  1173.     mov    lmem lxmsctl.lenlo,ax    ;e into control block
  1174.                     ;d in den Kontrollblock
  1175.     mov    lmem lxmsctl.lenhi,dx
  1176.     mov    ax,lmem lcurrdesc.swoffset    ;e swap offset
  1177.                         ;d Lese-Offset
  1178.     mov    lmem lxmsctl.destlo,ax         ;e into control block
  1179.                         ;d in den Kontrollblock
  1180.     mov    ax,lmem lcurrdesc.addr        ;e segment to swap
  1181.                         ;d Lese-Segment
  1182.     mov    lmem lxmsctl.desthi,ax
  1183.     mov    si,lxmsctl
  1184.     mov    ah,0bh
  1185.     call    lmem lprep.xmm        ; move it
  1186.     or    ax,ax
  1187.     jz    swinxms_error
  1188.     mov    ax,lmem lxmsctl.lenlo    ;e adjust source addr
  1189.                     ;d Quelladresse adjustieren
  1190.     add    lmem lxmsctl.srclo,ax
  1191.     mov    ax,lmem lxmsctl.lenhi
  1192.     adc    lmem lxmsctl.srchi,ax
  1193. ;
  1194.     cmp    lmem lcurrdesc.num_follow,0    ;e another MCB?
  1195.                         ;d noch ein MCB?
  1196.     je    swinxms_complete
  1197. ;
  1198.     mov    lmem lxmsctl.lenlo,TYPE mcbdesc
  1199.     mov    lmem lxmsctl.lenhi,0
  1200.     mov    lmem lxmsctl.desthi,ds
  1201.     mov    lmem lxmsctl.destlo,lcurrdesc
  1202.     mov    si,lxmsctl
  1203.     mov    ah,0bh
  1204.     call    lmem lprep.xmm        ; move it
  1205.     or    ax,ax
  1206.     jz    swinxms_error
  1207.     add    lmem lxmsctl.srclo,16    ; one paragraph
  1208.     adc    lmem lxmsctl.srchi,0
  1209. ;
  1210.     call    lmem cgetmcb
  1211.     jc    swinxms_error
  1212.     jmp    swinxms_main
  1213. ;
  1214. swinxms_complete:
  1215.     mov    ah,0ah            ;e release XMS frame
  1216.                     ;d Freigeben XMS-Speicher
  1217.     mov    dx,lmem lprep.handle       ; XMS handle
  1218.     call    lmem lprep.xmm
  1219.     ret
  1220. ;
  1221. swinxms_error:
  1222.     mov    ah,0ah            ;e release XMS frame on error
  1223.                     ;d Bei Fehler XMS-Speicher freigeben
  1224.     call    lmem lprep.xmm
  1225.     mov    ax,4c00h
  1226.     int    21h
  1227. ;
  1228. swapin_xms    endp
  1229. ;
  1230. swinxms_length    = offset $ - offset swapin_xms
  1231. ;
  1232. ;
  1233. ;e    swapin_file:    swap in from file.
  1234. ;d    swapin_file:    Wiederherstellen von Datei.
  1235. ;
  1236. swapin_file    proc    far
  1237. ;
  1238.     mov    dx,lprep.swapfilename
  1239.     mov    ax,3d00h            ; open file
  1240.     int    21h
  1241.     jc    swinfile_error2
  1242.     mov    bx,ax                ; file handle
  1243. ;
  1244. swinfile_main:
  1245.     push    ds
  1246.     mov    cx,lmem lcurrdesc.swsize    ;e size in paragraphs
  1247.                         ;d Blocklänge in Paragraphen
  1248.     mov    dx,lmem lcurrdesc.swoffset    ; swap offset
  1249.     mov    ds,lmem lcurrdesc.addr        ; segment to swap
  1250. ;
  1251. swinfile_loop:
  1252.     mov    ax,cx
  1253.     cmp    ah,8h            ;e above 32k?
  1254.                     ;d mehr als 32k?
  1255.     jbe    swinfile_ok        ;e go read if not
  1256.                     ;d lesen wenn nein
  1257.     mov    ax,800h            ;e else read 32k
  1258.                     ;d sonst 32k lesen
  1259. ;
  1260. swinfile_ok:
  1261.     sub    cx,ax            ;e remaining length
  1262.                     ;d Restlänge
  1263.     push    cx            ;e save it
  1264.                     ;d sichern
  1265.     push    ax            ;e and save paras to read
  1266.                     ;d Sichern Länge in Paragraphen
  1267.     mov    cl,4
  1268.     shl    ax,cl            ;e convert to bytes
  1269.                     ;d Konvertieren in Anzahl Bytes
  1270.     mov    cx,ax
  1271.     mov    ah,3fh            ; read
  1272.     int    21h
  1273.     jc    swinfile_error
  1274.     cmp    ax,cx
  1275.     jne    swinfile_error
  1276.     pop    cx            ;e paras read
  1277.                     ;d Gelesene Paragraphen
  1278.     mov    ax,ds
  1279.     add    ax,cx            ;e bump up dest segment
  1280.                     ;d Add. Kopierlänge auf Zielsegment
  1281.     mov    ds,ax
  1282.     pop    cx            ;e remaining length
  1283.                     ;d Restlänge
  1284.     or    cx,cx            ;e anything left?
  1285.                     ;d Noch etwas übrig?
  1286.     jnz    swinfile_loop        ;e go loop if yes
  1287.                     ;d Nochmal wenn ja
  1288. ;
  1289.     pop    ds
  1290.     cmp    lmem lcurrdesc.num_follow,0    ; another MCB?
  1291.                         ;d noch ein MCB?
  1292.     je    swinfile_complete    ;e ready if not
  1293.                     ;d Fertig wenn nein
  1294.     mov    cx,16            ;e read one paragraph
  1295.                     ;d einen Paragraphen lesen
  1296.     mov    dx,lcurrdesc
  1297.     mov    ah,3fh
  1298.     int    21h
  1299.     jc    swinfile_error1
  1300.     cmp    ax,cx
  1301.     jne    swinfile_error1
  1302. ;
  1303.     push    bx
  1304.     call    lmem cgetmcb
  1305.     pop    bx
  1306.     jc    swinfile_error1
  1307.     jmp    swinfile_main
  1308. ;
  1309. ;
  1310. swinfile_complete:
  1311.     mov    ah,3eh            ; close file
  1312.     int    21h
  1313.     mov    dx,lprep.swapfilename
  1314.     mov    ah,41h            ; delete file
  1315.     int    21h
  1316.     ret
  1317. ;
  1318. swinfile_error:
  1319.     pop    cx
  1320.     pop    cx
  1321.     pop    ds
  1322. swinfile_error1:
  1323.     mov    ah,3eh            ; close file
  1324.     int    21h
  1325. swinfile_error2:
  1326.     mov    dx,lprep.swapfilename
  1327.     mov    ah,41h            ; delete file
  1328.     int    21h
  1329.     mov    ax,4cffh
  1330.     int    21h
  1331. ;
  1332. swapin_file    endp
  1333. ;
  1334. swinfile_length    = offset $ - offset swapin_file
  1335. ;
  1336. ;
  1337. ;e    swapin_none:    no swap, return immediately.
  1338. ;d    swapin_none:    Kein Wiederherstellen, nur Rückkehr.
  1339. ;
  1340. swapin_none    proc    far
  1341. ;
  1342.     ret
  1343. ;
  1344. swapin_none    endp
  1345. ;
  1346. ;
  1347.     IF    swinems_length GT swinxms_length
  1348. swcodelen    =    swinems_length
  1349.     ELSE
  1350. swcodelen    =    swinxms_length
  1351.     ENDIF
  1352.     IF    swinfile_length GT swcodelen
  1353. swcodelen    =    swinfile_length
  1354.     ENDIF
  1355. ;
  1356. swap_codelen    =    ((swcodelen + 1) / 2) * 2
  1357. ;
  1358. codelen        =    base_length + swap_codelen
  1359. reslen        =    codebeg + codelen
  1360. keep_paras    =    (reslen + 15) shr 4    ;e paragraphs to keep
  1361.                         ;d Residente Paragraphen
  1362. swapbeg        =    keep_paras shl 4    ;e start of swap space
  1363.                         ;d Beginn Auslagerungsbereich
  1364. savespace    =    swapbeg - 5ch    ;e length of overwritten area
  1365.                     ;d Länge überschriebener Bereich
  1366. ;
  1367. ;--------------------------------------------------------------------
  1368. ;
  1369.     IFDEF    PASCAL
  1370.     .data
  1371.     ELSE
  1372.     IFDEF    TC_HUGE
  1373.     .fardata?    my_data
  1374.     ELSE
  1375.     .data?
  1376.     ENDIF
  1377.     ENDIF
  1378. ;
  1379. ;>e
  1380. ;    Space for saving the part of the memory image below the
  1381. ;    swap area that is overwritten by our code.
  1382. ;<
  1383. ;>d
  1384. ;    Platz zum Sichern des Teils des Speichers der vom 
  1385. ;    Aus-/Einlagerungscode und den Variablen überschrieben wird.
  1386. ;<
  1387. save_dat    db    savespace dup(?)
  1388. ;>e
  1389. ;    Variables used while swapping out.
  1390. ;    The "prep" structure is initialized by prep_swap.
  1391. ;<
  1392. ;>d
  1393. ;    Variablen zur Benutzung beim Auslagern.
  1394. ;    Die "prep" Struktur wird durch prep_swap initialisiert.
  1395. ;<
  1396. prep        prep_block    <>
  1397. nextmcb        mcbdesc        <>
  1398. currdesc    mcbdesc        <>
  1399. xmsctl        xms_control    <>
  1400. ems_curpage    dw        ?    ;e current EMS page number
  1401.                     ;d Laufende Nummer EMS-Seite
  1402. ems_curoff    dw        ?    ;e current EMS offset (paragraph)
  1403.                     ;d Laufender EMS Offset (Paragraph)
  1404. ;
  1405. ;--------------------------------------------------------------------
  1406. ;       
  1407.     .code
  1408. ;>e
  1409. ;    swapout_ems:    swap out an MCB block to EMS.
  1410. ;
  1411. ;    Entry:    "currdesc"     contains description of block to swap
  1412. ;        "nextmcb"    contains MCB-descriptor of next block
  1413. ;                if currdesc.num_follow is nonzero
  1414. ;
  1415. ;    Exit:    0 if OK, != 0 if error, Zero-flag set accordingly.
  1416. ;
  1417. ;    Uses:    All regs excpt DS
  1418. ;<
  1419. ;>d
  1420. ;    swapout_ems:    Auslagern eines MCB nach EMS.
  1421. ;
  1422. ;    Ein:    "currdesc"     Beschreibung des auszulagernden Blocks
  1423. ;        "nextmcb"    MCB-Deskriptor des nächsten Blocks
  1424. ;                wenn currdesc.num_follow nicht 0 ist.
  1425. ;
  1426. ;    Aus:    0 wenn OK, != 0 bei Fehler, Zero-flag entsprechend gesetzt.
  1427. ;
  1428. ;    Benutzt: Alle Register außer DS
  1429. ;<
  1430. swapout_ems    proc    near
  1431. ;
  1432.     push    ds
  1433.     mov    cx,currdesc.swsize    ;e block length in paras
  1434.                     ;d Blocklänge in Paragraphen
  1435.     mov    si,currdesc.swoffset    ; swap offset
  1436.     mov    dx,prep.handle        ; EMS handle
  1437.     mov    bx,ems_curpage        ;e current EMS page
  1438.                     ;d laufende EMS Seite
  1439.     mov    di,ems_curoff        ;e current EMS page offset (paras)
  1440.                     ;d laufender EMS Offset (Paragraph)
  1441.     mov    es,prep.ems_pageframe    ; page frame address
  1442.     mov    ds,currdesc.addr    ; segment to swap
  1443. ;
  1444.     mov    ax,ems_parasize        ;e max length
  1445.                     ;d Maximale Länge
  1446.     sub    ax,di            ;e minus current offset
  1447.                     ;d Minus laufender Offset
  1448.     jnz    swems_ok        ;e go copy if there's room
  1449.                     ;d Kopieren wenn noch Platz ist
  1450. ;
  1451. swems_loop:
  1452.     mov    ax,4400h        ;e map in next page
  1453.                     ;d Nächste EMS-Page einmappen
  1454.     int    EMM_INT
  1455.     or    ah,ah
  1456.     jnz    swems_error
  1457.     mov    di,0            ;e reset offset
  1458.                     ;d Offset zurücksetzen
  1459.     inc    bx            ;e bump up page number
  1460.                     ;d Seitennummer erhöhen
  1461.     mov    ax,ems_parasize        ;e max length to copy
  1462.                     ;d Maximale Länge
  1463. ;
  1464. swems_ok:
  1465.     cmp    ax,cx            ;e length to copy
  1466.                     ;d zu kopierende Länge
  1467.     jbe    swems_doit        ;e go do it if <= total length
  1468.                     ;d kopieren wenn <= Gesamtlänge
  1469.     mov    ax,cx            ;e else use total length
  1470.                     ;d sonst Gesamtlänge kopieren
  1471. ;
  1472. swems_doit:
  1473.     sub    cx,ax            ;e subtract copy length from total
  1474.                     ;d Gesamtlänge -= kopierte Länge
  1475.     push    cx            ;e and save
  1476.                     ;d sichern
  1477.     push    ax            ;e save the copy length in paras
  1478.                     ;d Sichern Kopierlänge in Paragraphen
  1479.     push    si
  1480.     push    di
  1481.     mov    cl,3
  1482.     shl    ax,cl            ;e convert to number of words (!)
  1483.                     ;d Konvertieren in Anzahl Worte (!)
  1484.     inc    cl
  1485.     shl    di,cl            ;e convert to byte address
  1486.                     ;d In Byte-Adresse konvertieren
  1487.     mov    cx,ax
  1488.     rep movsw
  1489.     pop    di
  1490.     pop    si
  1491.     pop    cx            ;e copy length in paras
  1492.                     ;d Kopierlänge in Paragraphen
  1493.     mov    ax,ds
  1494.     add    ax,cx            ;e add copy length to source segment
  1495.                     ;d Kopierlänge auf Zielsegment
  1496.     add    di,cx            ;e and EMS page offset
  1497.                     ;d und EMS-Seiten-Offset addieren
  1498.     mov    ds,ax
  1499.     pop    cx            ;e remaining length
  1500.                     ;d Restlänge
  1501.     or    cx,cx            ;e did we copy everything?
  1502.                     ;d Alles kopiert?
  1503.     jnz    swems_loop        ;e go loop if not
  1504.                     ;d Nochmal wenn nein
  1505. ;
  1506.     pop    ds
  1507.     cmp    currdesc.num_follow,0    ;e another MCB?
  1508.                     ;d noch ein MCB?
  1509.     je    swems_complete        ;e exit if not
  1510.                     ;d Fertig wenn nein
  1511. ;
  1512. ;e    Another MCB follows, append nextmcb to save block.
  1513. ;d    Ein weiterer MCB folgt, nextmcb an Block anfügen.
  1514. ;
  1515.     cmp    di,ems_parasize
  1516.     jb    swems_nonewpage        ;e no new block needed
  1517.                     ;d kein neuer Block nötig
  1518.     mov    ax,4400h        ; map page, phys = 0
  1519.     int    EMM_INT
  1520.     or    ah,ah
  1521.     jnz    swems_error1
  1522.     mov    di,0
  1523.     inc    bx
  1524. ;
  1525. swems_nonewpage:
  1526.     push    di
  1527.     mov    cl,4
  1528.     shl    di,cl            ;e convert to byte address
  1529.                     ;d in Byte-Adresse konvertieren
  1530.     mov    cx,TYPE mcbdesc
  1531.     mov    si,offset nextmcb
  1532.     rep movsb
  1533.     pop    di
  1534.     inc    di            ;e one paragraph
  1535.                     ;d Einen Paragraphen
  1536. ;
  1537. swems_complete:
  1538.     mov    ems_curpage,bx
  1539.     mov    ems_curoff,di
  1540.     xor    ax,ax
  1541.     ret
  1542. ;
  1543. swems_error:
  1544.     pop    ds
  1545. swems_error1:
  1546.     mov    ah,45h            ;e release EMS pages on error
  1547.                     ;d Bei Fehler EMS freigeben
  1548.     int    EMM_INT
  1549.     mov    ax,RC_SWAPERROR
  1550.     or    ax,ax
  1551.     ret
  1552. ;
  1553. swapout_ems    endp
  1554. ;
  1555. ;>e
  1556. ;    swapout_xms:    swap out an MCB block to XMS.
  1557. ;
  1558. ;    Entry:    "currdesc"     contains description of block to swap
  1559. ;        "nextmcb"    contains MCB-descriptor of next block
  1560. ;                if currdesc.num_follow is nonzero
  1561. ;
  1562. ;    Exit:    0 if OK, -1 if error, Zero-flag set accordingly.
  1563. ;
  1564. ;    Uses:    All regs excpt DS
  1565. ;<
  1566. ;>d
  1567. ;    swapout_xms:    Auslagern eines MCB nach XMS.
  1568. ;
  1569. ;    Ein:    "currdesc"     Beschreibung des auszulagernden Blocks
  1570. ;        "nextmcb"    MCB-Deskriptor des nächsten Blocks
  1571. ;                wenn currdesc.num_follow nicht 0 ist.
  1572. ;
  1573. ;    Aus:    0 wenn OK, != 0 bei Fehler, Zero-flag entsprechend gesetzt.
  1574. ;
  1575. ;    Benutzt: Alle Register außer DS
  1576. ;<
  1577. swapout_xms    proc    near
  1578. ;
  1579.     mov    ax,currdesc.swsize    ;e size in paragraphs
  1580.                     ;d Größe in Paragraphen
  1581.     mov    cl,4
  1582.     rol    ax,cl            ;e size in bytes + high nibble
  1583.                     ;d Größe in Bytes + high nibble
  1584.     mov    dx,ax
  1585.     and    ax,0fff0h        ; low word
  1586.     and    dx,0000fh        ; high word
  1587.     mov    xmsctl.lenlo,ax        ; into control block
  1588.     mov    xmsctl.lenhi,dx
  1589.     mov    xmsctl.srchnd,0        ;e source is normal memory
  1590.                     ;d Quelle ist Standardspeicher
  1591.     mov    ax,currdesc.swoffset    ; swap offset
  1592.     mov    xmsctl.srclo,ax        ; into control block
  1593.     mov    ax,currdesc.addr    ; segment to swap
  1594.     mov    xmsctl.srchi,ax
  1595.     mov    ax,prep.handle        ; XMS handle
  1596.     mov    xmsctl.desthnd,ax
  1597.     mov    si,offset xmsctl
  1598.     mov    ah,0bh
  1599.     call    prep.xmm        ; move it
  1600.     or    ax,ax
  1601.     jz    swxms_error
  1602.     mov    ax,xmsctl.lenlo        ;e adjust destination addr
  1603.                     ;d Zieladresse adjustieren
  1604.     add    xmsctl.destlo,ax
  1605.     mov    ax,xmsctl.lenhi
  1606.     adc    xmsctl.desthi,ax
  1607. ;
  1608.     cmp    currdesc.num_follow,0    ;e another MCB?
  1609.                     ;d noch ein MCB?
  1610.     je    swxms_complete
  1611. ;
  1612.     mov    xmsctl.lenlo,TYPE mcbdesc
  1613.     mov    xmsctl.lenhi,0
  1614.     mov    xmsctl.srchi,ds
  1615.     mov    xmsctl.srclo,offset nextmcb
  1616.     mov    si,offset xmsctl
  1617.     mov    ah,0bh
  1618.     call    prep.xmm        ; move it
  1619.     or    ax,ax
  1620.     jz    swxms_error
  1621.     add    xmsctl.destlo,16    ; one paragraph
  1622.     adc    xmsctl.desthi,0
  1623. ;
  1624. swxms_complete:
  1625.     xor    ax,ax
  1626.     ret
  1627. ;
  1628. swxms_error:
  1629.     mov    ah,0ah            ;e release XMS frame on error
  1630.                     ;d Bei Fehler XMS-Speicher freigeben
  1631.     mov    dx,prep.handle        ; XMS handle
  1632.     call    prep.xmm
  1633.     mov    ax,RC_SWAPERROR
  1634.     or    ax,ax
  1635.     ret
  1636. ;
  1637. swapout_xms    endp
  1638. ;
  1639. ;>e
  1640. ;    swapout_file:    swap out an MCB block to file.
  1641. ;
  1642. ;    Entry:    "currdesc"     contains description of block to swap
  1643. ;        "nextmcb"    contains MCB-descriptor of next block
  1644. ;                if currdesc.num_follow is nonzero
  1645. ;
  1646. ;    Exit:    0 if OK, -1 if error, Zero-flag set accordingly.
  1647. ;
  1648. ;    Uses:    All regs excpt DS
  1649. ;<
  1650. ;>d
  1651. ;    swapout_file:    Auslagern eines MCB auf Datei.
  1652. ;
  1653. ;    Ein:    "currdesc"     Beschreibung des auszulagernden Blocks
  1654. ;        "nextmcb"    MCB-Deskriptor des nächsten Blocks
  1655. ;                wenn currdesc.num_follow nicht 0 ist.
  1656. ;
  1657. ;    Aus:    0 wenn OK, != 0 bei Fehler, Zero-flag entsprechend gesetzt.
  1658. ;
  1659. ;    Benutzt: Alle Register außer DS
  1660. ;<
  1661. swapout_file    proc    near
  1662. ;
  1663.     push    ds
  1664.     mov    cx,currdesc.swsize    ;e size in paragraphs
  1665.                     ;d Blocklänge in Paragraphen
  1666.     mov    bx,prep.handle        ; file handle
  1667.     mov    dx,currdesc.swoffset    ; swap offset
  1668.     mov    ds,currdesc.addr    ; segment to swap
  1669. ;
  1670. swfile_loop:
  1671.     mov    ax,cx
  1672.     cmp    ah,8h            ;e above 32k?
  1673.                     ;d mehr als 32k?
  1674.     jbe    swfile_ok        ;e go write if not
  1675.                     ;d schreiben wenn nein
  1676.     mov    ax,800h            ;e else write 32k
  1677.                     ;d sonst 32k schreiben
  1678. ;
  1679. swfile_ok:
  1680.     sub    cx,ax            ;e remaining length
  1681.                     ;d Restlänge
  1682.     push    cx            ;e save it
  1683.                     ;d sichern
  1684.     push    ax            ;e and save paras to write
  1685.                     ;d Sichern Länge in Paragraphen
  1686.     mov    cl,4
  1687.     shl    ax,cl            ;e convert to bytes
  1688.                     ;d Konvertieren in Anzahl Bytes
  1689.     mov    cx,ax
  1690.     mov    ah,40h            ; write
  1691.     int    21h
  1692.     jc    swfile_error
  1693.     cmp    ax,cx
  1694.     jne    swfile_error
  1695.     pop    cx            ;e paras written
  1696.                     ;d Geschriebene Paragraphen
  1697.     mov    ax,ds
  1698.     add    ax,cx            ;e bump up source segment
  1699.                     ;d Add. Kopierlänge auf Quellsegment
  1700.     mov    ds,ax
  1701.     pop    cx            ;e remaining length
  1702.                     ;d Restlänge
  1703.     or    cx,cx            ;e anything left?
  1704.                     ;d Noch etwas übrig?
  1705.     jnz    swfile_loop        ;e go loop if yes
  1706.                     ;d Nochmal wenn ja
  1707. ;
  1708.     pop    ds
  1709.     cmp    currdesc.num_follow,0    ;e another MCB?
  1710.                     ;d noch ein MCB?
  1711.     je    swfile_complete        ;e ready if not
  1712.                     ;d Fertig wenn nein
  1713.     mov    cx,16            ;e write one paragraph
  1714.                     ;d einen Paragraphen schreiben
  1715.     mov    dx,offset nextmcb
  1716.     mov    ah,40h
  1717.     int    21h
  1718.     jc    swfile_error1
  1719.     cmp    ax,cx
  1720.     jne    swfile_error1
  1721. ;
  1722. swfile_complete:
  1723.     xor    ax,ax
  1724.     ret
  1725. ;
  1726. swfile_error:
  1727.     pop    cx
  1728.     pop    cx
  1729.     pop    ds
  1730. swfile_error1:
  1731.     mov    ah,3eh            ; close file
  1732.     int    21h
  1733.     mov    dx,offset prep.swapfilename
  1734.     mov    ah,41h            ; delete file
  1735.     int    21h
  1736.     mov    ax,RC_SWAPERROR
  1737.     or    ax,ax
  1738.     ret
  1739. ;
  1740. swapout_file    endp
  1741. ;
  1742. ;--------------------------------------------------------------------------
  1743. ;
  1744.     IF    REDIRECT
  1745. ;>e
  1746. ;    @redirect: Redirect a file.
  1747. ;
  1748. ;    Entry:    DS:SI = Filename pointer
  1749. ;        AX zero if filename is NULL
  1750. ;        CX    = Handle to redirect
  1751. ;        ES:DI = Handle save pointer
  1752. ;
  1753. ;    Exit:    Carry set on error, then AL has DOS error code
  1754. ;        ES:DI updated
  1755. ;
  1756. ;    Uses:    AX,BX,DX,SI
  1757. ;<
  1758. ;>d
  1759. ;    @redirect: Umleiten einer Datei.
  1760. ;
  1761. ;    Entry:    DS:SI = Zeiger auf Dateinamen
  1762. ;        AX ist 0 wenn Dateinamenszeiger NULL ist
  1763. ;        CX    = Umzuleitendes Handle
  1764. ;        ES:DI = Zeiger auf Handle-Sicherungswort
  1765. ;
  1766. ;    Exit:    Carry gesetzt bei Fehler, dann ist AL=DOS-Fehlercode
  1767. ;        ES:DI wird modifiziert.
  1768. ;
  1769. ;    Uses:    AX,BX,DX,SI
  1770. ;<
  1771. @redirect    proc    near
  1772.         local    doserr
  1773. ;
  1774.     or    ax,ax
  1775.     jz    no_redirect
  1776.     cmp    byte ptr [si],0
  1777.     jne    do_redirect
  1778. ;
  1779. no_redirect:
  1780.     mov    ax,-1
  1781.     stosw
  1782.     ret
  1783. ;
  1784. do_redirect:
  1785.     IFDEF    PASCAL
  1786.     inc    si            ;e skip length byte
  1787.                     ;d Längenbyte überspringen
  1788.     ENDIF
  1789.     or    cx,cx
  1790.     jnz    redir_write
  1791.     mov    dx,si
  1792.     mov    ax,3d00h    ; open file, read only
  1793.     int    21h
  1794.     mov    doserr,ax
  1795.     jc    redir_failed
  1796. ;
  1797. redir_ok:
  1798.     mov    dx,ax
  1799.     mov    ah,45h        ; duplicate handle
  1800.     mov    bx,cx
  1801.     int    21h
  1802.     mov    doserr,ax
  1803.     jc    redir_failed_dup
  1804.     push    ax
  1805.     mov    bx,dx
  1806.     mov    ah,46h        ; force duplicate handle
  1807.     int    21h
  1808.     mov    doserr,ax
  1809.     pop    ax
  1810.     jc    redir_failed_force
  1811.     stosw
  1812.     ret
  1813. ;
  1814. redir_failed_force:
  1815.     mov    bx,ax
  1816.     mov    ah,3eh        ; close file
  1817.     int    21h
  1818. ;
  1819. redir_failed_dup:
  1820.     mov    bx,dx
  1821.     mov    ah,3eh        ; close file
  1822.     int    21h
  1823. ;
  1824. redir_failed:
  1825.     mov    ax,doserr
  1826.     stc
  1827.     ret
  1828. ;
  1829. redir_write:
  1830.     cmp    byte ptr [si],'>'
  1831.     jne    no_append
  1832.     inc    si
  1833.     mov    dx,si
  1834.     mov    ax,3d02h        ; open file, read/write
  1835.     int    21h
  1836.     jc    no_append
  1837.     mov    bx,ax
  1838.     push    cx
  1839.     mov    ax,4202h        ; move file, offset from EOF
  1840.     xor    cx,cx
  1841.     mov    dx,cx
  1842.     int    21h
  1843.     mov    doserr,ax
  1844.     pop    cx
  1845.     mov    ax,bx
  1846.     jnc    redir_ok
  1847.     mov    dx,ax
  1848.     jmp    redir_failed_dup
  1849. ;
  1850. no_append:
  1851.     mov    dx,si
  1852.     mov    ah,3ch
  1853.     push    cx
  1854.     xor    cx,cx
  1855.     int    21h
  1856.     mov    doserr,ax
  1857.     pop    cx
  1858.     jc    redir_failed
  1859.     jmp    redir_ok
  1860. ;
  1861. @redirect    endp
  1862. ;
  1863.     ENDIF
  1864. ;
  1865. ;--------------------------------------------------------------------------
  1866. ;--------------------------------------------------------------------------
  1867. ;
  1868. ;
  1869.     IFDEF    PASCAL
  1870.     IFDEF    FARCALL
  1871. do_spawn    PROC    far swapping: word, execfname: dword, params: dword, envlen: word, envp: dword, stdin: dword, stdout: dword, stderr: dword
  1872.     ELSE
  1873. do_spawn    PROC    near swapping: word, execfname: dword, params: dword, envlen: word, envp: dword, stdin: dword, stdout: dword, stderr: dword
  1874.     ENDIF
  1875.     ELSE
  1876. do_spawn    PROC    uses si di,swapping: word, execfname:ptr byte,params:ptr byte,envlen:word,envp:ptr byte,stdin:ptr byte, stdout:ptr byte, stderr:ptr byte
  1877.     ENDIF
  1878.     local    datseg,pspseg,currmcb
  1879. ;
  1880.     IFDEF    TC_HUGE
  1881.     mov    ax,SEG my_data
  1882.     mov    ds,ax
  1883.     ENDIF
  1884. ;
  1885.     mov    datseg,ds        ;e save default DS
  1886.                     ;d Default-DS sichern
  1887. ;
  1888.     IFDEF    PASCAL
  1889.     cld
  1890.     mov    bx,prefixseg
  1891.     ELSE
  1892.     IFDEF    TC_HUGE
  1893.     mov    ax,SEG _psp
  1894.     mov    es,ax
  1895.     mov    bx,es:_psp
  1896.     ELSE
  1897.     mov    bx,_psp
  1898.     ENDIF
  1899.     ENDIF
  1900.     mov    pspseg,bx
  1901. ;
  1902. ;
  1903. ;e    Check if spawn is too low in memory
  1904. ;d    Prüfen ob dieses Modul zu weit unten im Speicher liegt
  1905. ;
  1906.     mov    ax,cs
  1907.     mov    dx,offset lowcode_begin
  1908.     mov    cl,4
  1909.     shr    dx,cl
  1910.     add    ax,dx            ;e normalized start of this code
  1911.                     ;d Normalisierter Beginn des Codes
  1912.     mov    dx,keep_paras        ;e the end of the modified area
  1913.                     ;d Ende des modifizierten Bereichs
  1914.     add    dx,bx            ;e plus PSP = end paragraph
  1915.                     ;d plus PSP = letzer Paragraph
  1916.     cmp    ax,dx
  1917.     ja    doswap_ok    ;e ok if start of code > end of low mem
  1918.                 ;d OK wenn Code-Beginn > Ende residenter Teil
  1919.     mov    ax,RC_TOOLOW
  1920.     ret
  1921. ;
  1922. doswap_ok:
  1923.     cmp    swapping,0
  1924.     jle    method_ok
  1925. ;
  1926. ;e    check the swap method, to make sure prep_swap has been called
  1927. ;d    Prüfen Auslagerungsmethode um sicherzustellen daß prep_swap
  1928. ;d    aufgerufen wurde.
  1929. ;
  1930.     mov    al,prep.swapmethod
  1931.     cmp    al,USE_EMS
  1932.     je    method_ok
  1933.     cmp    al,USE_XMS
  1934.     je    method_ok
  1935.     cmp    al,USE_FILE
  1936.     je    method_ok
  1937.     mov    ax,RC_BADPREP
  1938.     ret
  1939. ;>e
  1940. ;    Save the memory below the swap space.
  1941. ;    We must do this before swapping, so the saved memory is
  1942. ;    in the swapped out image.
  1943. ;    Anything else we'd want to save on the stack or anywhere
  1944. ;    else in "normal" memory also has to be saved here, any
  1945. ;    modifications done to memory after the swap will be lost.
  1946. ;
  1947. ;    Note that the memory save is done even when not swapping,
  1948. ;    because we use some of the variables in low core for
  1949. ;    simplicity.
  1950. ;<
  1951. ;>d
  1952. ;    Sichern des Speichers unterhalb des Auslagerungsbereichs.
  1953. ;    Dies muß vor dem Auslagern geschehen damit der gesicherte
  1954. ;    Bereich mit im Ausgelagerten Abbild ist.
  1955. ;    Auch alles Andere das auf dem Stack oder sonst im "normalen"
  1956. ;    Speicher gesichert werden soll muß hier gesichert werden,
  1957. ;    da alle Modifikationen des Speichers die nach dem Auslagern
  1958. ;    erfolgen verloren gehen.
  1959. ;
  1960. ;    Das Sichern des Speichers ist auch notwendig wenn keine Auslagerung
  1961. ;    stattfindet, da Teile des sonst residenten Bereichs im unteren
  1962. ;    Speicher in jedem Fall verwendet werden.
  1963. ;<
  1964. method_ok:
  1965.     mov    es,datseg
  1966.     mov    ds,pspseg        ;e DS points to PSP
  1967.                     ;d DS zeigt auf PSP
  1968.     mov    si,5ch
  1969.     mov    di,offset save_dat
  1970.     mov    cx,savespace / 2    ;e NOTE: savespace is always even
  1971.                     ;d HINWEIS: savespace ist stets gerade
  1972.     rep movsw
  1973. ;
  1974. ;
  1975.     mov    ds,datseg
  1976.     mov    ax,swapping
  1977.     cmp    ax,0
  1978.     jg    begin_swap
  1979. ;>e
  1980. ;    not swapping, prep_swap wasn't called. Init those variables in
  1981. ;      the 'prep' block we need in any case.
  1982. ;<
  1983. ;>d
  1984. ;    Keine Auslagerung, prep_swap wurde nicht aufgerufen. Die Variablen
  1985. ;    im 'prep'-Block initialisieren die in jedem Fall gebraucht werden.
  1986. ;<
  1987.     mov    prep.swapmethod,al
  1988.     je    no_reduce
  1989. ;
  1990.     mov    ax,pspseg
  1991.     dec    ax
  1992.     mov    prep.psp_mcb,ax
  1993.     mov    prep.first_mcb,ax
  1994.     inc    ax
  1995.     mov    es,ax
  1996.     mov    bx,es:psp_envptr
  1997.     mov    prep.env_mcb,bx
  1998.     mov    prep.noswap_mcb,0
  1999.     cmp    envlen,0
  2000.     jne    swp_can_swap_env
  2001.     mov    prep.noswap_mcb,bx
  2002. ;
  2003. swp_can_swap_env:
  2004.     xor    bx,bx
  2005.     mov    es,bx
  2006.     mov    ah,52h            ; get list of lists
  2007.     int    21h
  2008.     mov    ax,es
  2009.     or    ax,bx
  2010.     jz    no_reduce
  2011.     mov    es,es:[bx-2]        ; first MCB
  2012.     cmp    es:id,4dh        ; normal ID?
  2013.     jne    no_reduce
  2014.     mov    prep.first_mcb,es
  2015. ;
  2016. no_reduce:
  2017.     jmp    no_swap1
  2018. ;
  2019. ;e    set up first block descriptor
  2020. ;d    Ersten Block-Deskriptor aufsetzen
  2021. ;
  2022. begin_swap:
  2023.     mov    ax,prep.first_mcb
  2024.     mov    currmcb,ax
  2025.     mov    es,prep.psp_mcb        ;e let ES point to base MCB
  2026.                     ;d ES zeigt auf Basis-MCB
  2027.     mov    ax,es:paras
  2028.     mov    currdesc.msize,ax
  2029.     sub    ax,keep_paras
  2030.     mov    currdesc.swsize,ax
  2031.     mov    currdesc.addr,es
  2032.     mov    currdesc.swoffset,swapbeg + 16
  2033. ;e        NOTE: swapbeg is 1 para higher when seen from MCB
  2034. ;d        HINWEIS: swapbeg ist 1 Paragraph höher vom MCB aus gesehen
  2035.     mov    ax,prep.total_mcbs
  2036.     mov    currdesc.num_follow,ax
  2037. ;
  2038. ;e    init other vars
  2039. ;d    andere Variablen initialisieren
  2040. ;
  2041.     mov    xmsctl.destlo,0
  2042.     mov    xmsctl.desthi,0
  2043.     mov    ems_curpage,0
  2044.     mov    ems_curoff,ems_parasize
  2045. ;>e
  2046. ;    Do the swapping. Each MCB block (except the last) has an 
  2047. ;    "mcbdesc" structure appended that gives location and size 
  2048. ;    of the next MCB.
  2049. ;<
  2050. ;>d
  2051. ;    Auslagerung ausführen. An jeden MCB-Block (außer den letzten)
  2052. ;    wird eine "mcbdesc" Struktur zur Beschreibung von Adresse und
  2053. ;    Größe des nächsten Blocks angefügt.
  2054. ;<
  2055. swapout_main:
  2056.     cmp    currdesc.num_follow,0    ;e next block?
  2057.                     ;d Gibt es einen nächsten?
  2058.     je    swapout_no_next        ;e ok if not
  2059.                     ;d OK wenn nein
  2060. ;>e
  2061. ;    There is another MCB block to be saved. So we don't have
  2062. ;    to do two calls to the save routine with complicated
  2063. ;    parameters, we set up the next MCB descriptor beforehand.
  2064. ;    Walk the MCB chain starting at the current MCB to find
  2065. ;    the next one belonging to this process.
  2066. ;<
  2067. ;>d
  2068. ;    Es gibt einen weiteren auszulagernden MCB-Block. Um die 
  2069. ;    Auslagerungsroutine nicht getrennt für den MCB-Deskriptor
  2070. ;    aufrufen zu müssen (mit einer entsprechend aufwendigeren
  2071. ;    Parameterversorgung), wird der Deskriptor für den Folgeblock
  2072. ;    vor Aufruf erstellt.
  2073. ;    Dazu muß die MCB-Kette, beginnend beim derzeitigen Block,
  2074. ;    durchgegangen werden um den nächsten zum Prozeß gehörenden
  2075. ;    Block zu finden.
  2076. ;<
  2077.     mov    ax,currmcb
  2078.     mov    bx,pspseg
  2079.     mov    cx,prep.psp_mcb
  2080.     mov    dx,prep.noswap_mcb
  2081. ;
  2082. swm_mcb_walk:
  2083.     mov    es,ax
  2084.     cmp    ax,cx
  2085.     je    swm_next_mcb
  2086.     cmp    ax,dx
  2087.     je    swm_next_mcb
  2088. ;
  2089.     cmp    bx,es:owner        ;e our process?
  2090.                     ;d Dieser Prozeß?
  2091.     je    swm_mcb_found        ;e found it if yes
  2092.                     ;d gefunden wenn ja
  2093. ;
  2094. swm_next_mcb:
  2095.     cmp    es:id,4dh        ;e normal block?
  2096.                     ;d Normaler Block?
  2097.     jne    swm_mcb_error        ;e error if end of chain
  2098.                     ;d Fehler wenn Ende der Kette
  2099.     add    ax,es:paras        ; start + length
  2100.     inc    ax            ; next MCB
  2101.     jmp    swm_mcb_walk
  2102. ;
  2103. ;e    MCB found, set up an mcbdesc in the "nextmcb" structure
  2104. ;d    MCB gefunden, aufsetzen mcbdesc in der "nextmcb" Struktur
  2105. ;
  2106. swm_mcb_found:
  2107.     mov    nextmcb.addr,es
  2108.     mov    ax,es:paras        ;e get number of paragraphs
  2109.                     ;d Anzahl Paragraphen
  2110.     mov    nextmcb.msize,ax    ;e and save
  2111.                     ;d sichern
  2112.     inc    ax
  2113.     mov    nextmcb.swsize,ax
  2114.     mov    bx,es
  2115.     add    bx,ax
  2116.     mov    currmcb,bx
  2117.     mov    nextmcb.swoffset,0
  2118.     mov    ax,currdesc.num_follow
  2119.     dec    ax
  2120.     mov    nextmcb.num_follow,ax
  2121. ;
  2122. swapout_no_next:
  2123.     cmp    prep.swapmethod,USE_EMS
  2124.     je    swm_ems
  2125.     cmp    prep.swapmethod,USE_XMS
  2126.     je    swm_xms
  2127.     call    swapout_file
  2128.     jmp    short swm_next
  2129. ;
  2130. swm_ems:
  2131.     call    swapout_ems
  2132.     jmp    short swm_next
  2133. ;
  2134. swm_xms:
  2135.     call    swapout_xms
  2136. ;
  2137. swm_next:
  2138.     jnz    swapout_error
  2139.     cmp    currdesc.num_follow,0
  2140.     je    swapout_complete
  2141. ;>e
  2142. ;    next MCB exists, copy the "nextmcb" descriptor into
  2143. ;    currdesc, and loop.
  2144. ;<
  2145. ;>d
  2146. ;    Es gibt einen Folgeblock, der "nextmcb" Deskriptor wird in den
  2147. ;    "currdesc" Deskriptor kopiert, und das ganze noch mal von vorn.
  2148. ;<
  2149.     mov    es,datseg
  2150.     mov    si,offset nextmcb
  2151.     mov    di,offset currdesc
  2152.     mov    cx,TYPE mcbdesc
  2153.     rep movsb
  2154.     jmp    swapout_main
  2155. ;
  2156. ;
  2157. swm_mcb_error:
  2158.     mov    ax,RC_MCBERROR
  2159. ;
  2160. swapout_kill:
  2161.     cmp    swapping,0
  2162.     jl    swapout_error
  2163.     push    ax
  2164.     cmp    prep.swapmethod,USE_FILE
  2165.     je    swm_mcberr_file
  2166.     cmp    prep.swapmethod,USE_EMS
  2167.     je    swm_mcberr_ems
  2168. ;
  2169.     mov    ah,0ah            ;e release XMS frame on error
  2170.                     ;d Bei Fehler XMS-Block freigeben
  2171.     mov    dx,prep.handle        ; XMS handle
  2172.     call    prep.xmm
  2173.     pop    ax
  2174.     jmp    short swapout_error
  2175. ;
  2176. swm_mcberr_ems:
  2177.     mov    dx,prep.handle        ; EMS handle
  2178.     mov    ah,45h            ;e release EMS pages on error
  2179.                     ;d Bei Fehler EMS freigeben
  2180.     int    EMM_INT
  2181.     pop    ax
  2182.     jmp    short swapout_error
  2183. ;
  2184. swm_mcberr_file:
  2185.     mov    bx,prep.handle
  2186.     cmp    bx,-1
  2187.     je    swm_noclose
  2188.     mov    ah,3eh            ; close file
  2189.     int    21h
  2190. swm_noclose:
  2191.     mov    dx,offset prep.swapfilename
  2192.     mov    ah,41h            ; delete file
  2193.     int    21h
  2194.     pop    ax
  2195. ;
  2196. swapout_error:
  2197.     ret
  2198. ;
  2199. ;>e
  2200. ;    Swapout complete. Close the handle (EMS/file only),
  2201. ;    then set up low memory.
  2202. ;<
  2203. ;>d
  2204. ;    Auslagerung abgeschlossen. Die Datei bzw. die EMS-Seite wird
  2205. ;    geschlossen, und der residente Bereich wird initialisiert.
  2206. ;<
  2207. swapout_complete:
  2208.     cmp    prep.swapmethod,USE_FILE
  2209.     jne    swoc_nofile
  2210. ;
  2211. ;e    File swap: Close the swap file to make the handle available
  2212. ;d    Auslagerung auf Datei: Datei schließen um den Handle freizumachen
  2213. ;
  2214.     mov    bx,prep.handle
  2215.     mov    prep.handle,-1
  2216.     mov    ah,3eh
  2217.     int    21h            ; close file
  2218.     mov    si,offset swapin_file
  2219.     jnc    swoc_ready
  2220.     mov    ax,RC_SWAPERROR
  2221.     jmp    swapout_kill
  2222. ;
  2223. swoc_nofile:
  2224.     cmp    prep.swapmethod,USE_EMS
  2225.     jne    swoc_xms
  2226. ;
  2227. ;e    EMS: Unmap page
  2228. ;d    EMS: Seite unzugänglich machen
  2229. ;
  2230.     mov    ax,4400h
  2231.     mov    bx,-1
  2232.     mov    dx,prep.handle
  2233.     int    EMM_INT
  2234.     mov    si,offset swapin_ems
  2235.     jmp    short swoc_ready
  2236. ;
  2237. swoc_xms:
  2238.     mov    si,offset swapin_xms
  2239.     jmp    short swoc_ready
  2240. ;
  2241. no_swap1:
  2242.     mov    si,offset swapin_none
  2243. ;    
  2244. ;e    Copy the appropriate swap-in routine to low memory.
  2245. ;d    Kopieren der der Auslagerungsmethode entsprechenden Routine
  2246. ;d    in den residenten Teil.
  2247. ;
  2248. swoc_ready:
  2249.     mov    es,pspseg
  2250.     mov    cx,swap_codelen / 2
  2251.     mov    di,codebeg + base_length
  2252.     push    ds
  2253.     mov    ax,cs
  2254.     mov    ds,ax
  2255.     rep movsw
  2256. ;>e
  2257. ;    And while we're at it, copy the MCB allocation routine (which
  2258. ;    also includes the initial MCB release and exec call) down.
  2259. ;<
  2260. ;>d
  2261. ;    Außerdem die MCB-Allozierungsroutine und den EXEC-Aufruf
  2262. ;    nach unten kopieren.
  2263. ;<
  2264.     mov    cx,base_length / 2
  2265.     mov    di,param_len
  2266.     mov    si,offset lowcode_begin
  2267.     rep movsw
  2268. ;
  2269.     pop    ds
  2270.     mov    bx,es
  2271.     dec    bx
  2272.     mov    es,bx        ;e let ES point to base MCB
  2273.                 ;d ES zeigt jetzt auf den Basisblock
  2274. ;>e
  2275. ;    Again set up the base MCB descriptor, and copy it as well as
  2276. ;    the variables set up by prep_swap to low memory.
  2277. ;    This isn't too useful if we're not swapping, but it doesn't
  2278. ;    hurt, either. The only variable used when not swapping is
  2279. ;    lprep.swapmethod.
  2280. ;<
  2281. ;>d
  2282. ;    Der Deskriptor für den Basisblock wird erneut aufgesetzt und,
  2283. ;    zusammen mit dem Variablenblock der durch prep_swap initialisiert
  2284. ;    wurde, nach unten kopieren.
  2285. ;    Wenn gar nicht ausgelagert wird, ist dies eigentlich nicht nicht
  2286. ;    notwendig, es schadet aber auch nicht. Die einzige Variable
  2287. ;    die in diesem Fall benötigt wird ist lprep.swapmethod.
  2288. ;<
  2289.     mov    ax,es:paras
  2290.     mov    currdesc.msize,ax
  2291.     sub    ax,keep_paras
  2292.     mov    currdesc.swsize,ax
  2293.     mov    currdesc.addr,es
  2294.     mov    currdesc.swoffset,swapbeg + 16
  2295.     mov    ax,prep.total_mcbs
  2296.     mov    currdesc.num_follow,ax
  2297. ;
  2298.     mov    es,pspseg        ;e ES points to PSP again
  2299.                     ;d ES zeigt wieder auf PSP
  2300. ;
  2301.     mov    cx,TYPE prep_block
  2302.     mov    si,offset prep
  2303.     mov    di,lprep
  2304.     rep movsb
  2305.     mov    cx,TYPE mcbdesc
  2306.     mov    si,offset currdesc
  2307.     mov    di,lcurrdesc
  2308.     rep movsb
  2309. ;
  2310. ;e    now set up other variables in low core
  2311. ;d    Nun werden die weiteren Variablen im residenten Tail initialisiert.
  2312. ;
  2313.     mov    ds,pspseg
  2314.     mov    ds:cgetmcb,getmcboff + codebeg
  2315.     mov    ds:eretcode,0
  2316.     mov    ds:retflags,0
  2317. ;>e
  2318. ;    If 'NO_INHERIT' is nonzero, save the entries of the 
  2319. ;    handle table, and set the last 15 to 0ffh (unused).
  2320. ;<
  2321. ;>d
  2322. ;    Wenn 'NO_INHERIT' nicht 0 ist, Retten der Handle-Tabelle
  2323. ;    und Setzen der letzten 15 Einträge auf 0ffh (unbenutzt).
  2324. ;<
  2325.     IF    NO_INHERIT
  2326.     mov    si,psp_handletab
  2327.     mov    di,lhandlesave
  2328.     mov    cx,10
  2329.     rep movsw
  2330.     mov    si,psp_handlenum    ;e Length of handle table
  2331.                     ;d Länge Handle-Tabelle
  2332.     mov    ax,[si]
  2333.     stosw
  2334.     mov    word ptr [si],20    ;e set to default to be safe
  2335.                     ;d Auf Standardwert setzten
  2336.     add    si,2
  2337.     lodsw                ;e Handle table pointer
  2338.                     ;d Zeiger auf Handle-Tabelle
  2339.     mov    bx,ax
  2340.     stosw
  2341.     lodsw
  2342.     stosw
  2343.     cmp    ax,pspseg
  2344.     jne    copy_handles
  2345.     cmp    bx,psp_handletab
  2346.     je    no_handlecopy
  2347. ;>e
  2348. ;    if the handle table pointer in the PSP does not point to
  2349. ;    the default PSP location, copy the first five entries from
  2350. ;    this table into the PSP - but only if we have DOS >= 3.0.
  2351. ;<
  2352. ;>d
  2353. ;    Wenn der Handle-Tabellen-Pointer im PSP nicht auf den
  2354. ;    Standard-Platz im PSP zeigt, die ersten fünf Einträge
  2355. ;    aus dieser Tabelle in den PSP kopieren - aber nur bei
  2356. ;    einer DOS-Version >= 3.0.
  2357. ;<
  2358. copy_handles:
  2359.     mov    ds,ax
  2360.     mov    si,bx
  2361.     mov    ax,3000h        ; get DOS version
  2362.     int    21h
  2363.     cmp    al,3
  2364.     jb    no_handlecopy
  2365.     mov    di,psp_handletab
  2366.     mov    es:psp_handleptro,di
  2367.     mov    es:psp_handleptrs,es
  2368.     movsw
  2369.     movsw
  2370.     movsb
  2371. ;
  2372. no_handlecopy:
  2373.     mov    di,psp_handletab+5
  2374.     mov    ax,0ffffh
  2375.     stosb
  2376.     mov    cx,7
  2377.     rep stosw
  2378. ;
  2379.     ENDIF
  2380. ;
  2381. ;e    Handle Redirection
  2382. ;d    Dateiumleitung behandeln
  2383. ;
  2384.     IF    REDIRECT
  2385.     mov    es,pspseg
  2386.     mov    di,lstdinsav
  2387.     mov    ax,-1
  2388.     stosw
  2389.     stosw
  2390.     stosw
  2391.     mov    di,lstdinsav
  2392.     xor    cx,cx
  2393.     IF    ptrsize
  2394.     lds    si,stdin
  2395.     mov    ax,ds
  2396.     or    ax,si
  2397.     ELSE
  2398.     mov    si,stdin
  2399.     mov    ds,datseg
  2400.     or    si,si
  2401.     ENDIF
  2402.     call    @redirect
  2403.     jc    failed_redir
  2404.     inc    cx
  2405.     IF    ptrsize
  2406.     lds    si,stdout
  2407.     mov    ax,ds
  2408.     or    ax,si
  2409.     ELSE
  2410.     mov    si,stdout
  2411.     or    si,si
  2412.     ENDIF
  2413.     call    @redirect
  2414.     jc    failed_redir
  2415.     inc    cx
  2416.     IF    ptrsize
  2417.     lds    si,stderr
  2418.     mov    ax,ds
  2419.     or    ax,si
  2420.     ELSE
  2421.     mov    si,stderr
  2422.     or    si,si
  2423.     ENDIF
  2424.     call    @redirect
  2425.     jnc    redir_complete
  2426. ;
  2427. failed_redir:
  2428.     push    ax
  2429. ;
  2430. ;e    restore handle table and pointer
  2431. ;d    Wiederherstellen Handle-Tabelle und Pointer
  2432. ;
  2433.     mov    ds,pspseg
  2434.     mov    si,lstdinsav
  2435.     xor    cx,cx
  2436. ;
  2437. redirclose:
  2438.     lodsw
  2439.     cmp    ax,-1
  2440.     je    redclosenext
  2441.     mov    bx,ax
  2442.     mov    ah,46h
  2443.     int    21h
  2444. ;
  2445. redclosenext:
  2446.     inc    cx
  2447.     cmp    cx,3
  2448.     jb    redirclose
  2449. ;
  2450.     IF    NO_INHERIT
  2451.     mov    ds,pspseg
  2452.     mov    es,pspseg
  2453.     mov    si,lhandlesave
  2454.     mov    di,psp_handletab
  2455.     mov    cx,10
  2456.     rep movsw
  2457.     mov    di,psp_handlenum
  2458.     movsw
  2459.     movsw
  2460.     movsw
  2461.     ENDIF
  2462. ;
  2463. ;e    Restore overwritten part of program
  2464. ;d    Den überschriebenen Teil des Programms wiederherstellen
  2465. ;
  2466.     mov    ds,datseg
  2467.     mov    es,pspseg
  2468.     mov    si,offset save_dat
  2469.     mov    di,5ch
  2470.     mov    cx,savespace
  2471.     rep movsb
  2472. ;
  2473.     pop    ax
  2474.     mov    ah,RC_REDIRFAIL SHR 8
  2475.     jmp    swapout_kill
  2476. ;
  2477. redir_complete:
  2478.     IF    NO_INHERIT
  2479.     mov    ds,pspseg
  2480.     mov    es,pspseg
  2481.     mov    si,psp_handletab+5
  2482.     mov    di,lredirsav
  2483.     mov    cx,3
  2484.     rep movsw
  2485.     mov    di,psp_handletab+5
  2486.     mov    cx,3
  2487.     mov    ax,0ffffh
  2488.     rep stosw
  2489.     ENDIF
  2490.     ENDIF
  2491. ;
  2492. ;e    Prepare exec parameter block
  2493. ;d    Parameterblock für EXEC-Aufruf vorbereiten
  2494. ;
  2495.     mov    ax,es
  2496.     mov    es:expar.fcb1seg,ax
  2497.     mov    es:expar.fcb2seg,ax
  2498.     mov    es:expar.pparseg,ax
  2499.     mov    es:expar.envseg,0
  2500. ;>e
  2501. ;    The 'zero' word is located at 80h in the PSP, the start of
  2502. ;    the command line. So as not to confuse MCB walking programs,
  2503. ;    a command line length of zero is inserted here.
  2504. ;<
  2505. ;>d
  2506. ;    Das 'zero'-Wort ist an Adresse 80h im PSP, dem Beginn der
  2507. ;    Kommandozeile. Um Programme die die MCB-Kette abarbeiten
  2508. ;    und dabei möglicherweise auf diese Kommandozeile zugreifen
  2509. ;    nicht zu verwirren, wird eine leere Kommandozeile eingefügt.
  2510. ;<
  2511.     mov    es:zero,0d00h        ;e 00h,0dh = empty command line
  2512.                     ;d 00h,0dh = Leere Kommandozeile
  2513. ;
  2514. ;e    Init default fcb's by parsing parameter string
  2515. ;d    Default FCB-Blöcke aus dem Parameter-String füllen
  2516. ;
  2517.     IF    ptrsize
  2518.     lds    si,params
  2519.     ELSE
  2520.     mov    si,params
  2521.     mov    ds,datseg
  2522.     ENDIF
  2523.     IFDEF    PASCAL
  2524.     inc    si            ;e skip length byte
  2525.                     ;d Längenbyte überspringen
  2526.     ENDIF
  2527.     push    si
  2528.     mov    di,xfcb1
  2529.     mov    es:expar.fcb1,di
  2530.     push    di
  2531.     mov    cx,16
  2532.     xor    ax,ax
  2533.     rep stosw            ;e init both fcb's to 0
  2534.                     ;d Beide FCBs mit 0 vorbesetzen
  2535.     pop    di
  2536.     mov    ax,2901h
  2537.     int    21h
  2538.     mov    di,xfcb2
  2539.     mov    es:expar.fcb2,di
  2540.     mov    ax,2901h
  2541.     int    21h
  2542.     pop    si
  2543. ;
  2544. ;e    move command tail string into low core
  2545. ;d    Kommandozeile in residenten Teil transferieren
  2546. ;
  2547.     mov    di,progpars
  2548.     mov    es:expar.ppar,di
  2549.     xor    cx,cx
  2550.     inc    di
  2551. cmdcpy:
  2552.     lodsb
  2553.     or    al,al
  2554.     jz    cmdcpy_end
  2555.     stosb
  2556.     inc    cx
  2557.     jmp    cmdcpy
  2558. ;
  2559. cmdcpy_end:
  2560.     mov    al,0dh
  2561.     stosb
  2562.     mov    es:progpars,cl
  2563. ;
  2564. ;e    move filename string into low core
  2565. ;d    Dateinamen in residenten Teil transferieren
  2566. ;
  2567.     IF    ptrsize
  2568.     lds    si,execfname
  2569.     ELSE
  2570.     mov    si,execfname
  2571.     ENDIF
  2572.     IFDEF    PASCAL
  2573.     inc    si
  2574.     ENDIF
  2575.     mov    di,filename
  2576. fncpy:
  2577.     lodsb
  2578.     stosb
  2579.     or    al,al
  2580.     jnz    fncpy
  2581. ;
  2582. ;e    Setup environment copy
  2583. ;d    Umgebungsvariablenblock-Kopie aufsetzen
  2584. ;
  2585.     mov    bx,keep_paras        ;e paras to keep
  2586.                     ;d Residente Paragraphen
  2587.     mov    cx,envlen        ;e environment size
  2588.                     ;d Größe Umgebungsvariablen
  2589.     jcxz    no_environ        ;e go jump if no environment
  2590.                     ;d Fertig wenn keine Umgebung
  2591.     cmp    swapping,0
  2592.     jne    do_envcopy
  2593. ;>e
  2594. ;    Not swapping, use the environment pointer directly.
  2595. ;    Note that the environment copy must be paragraph aligned.
  2596. ;<
  2597. ;>d
  2598. ;    Keine Auslagerung, der Umgebungs-Zeiger kann direkt verwendet
  2599. ;    werden. Dazu muß die Kopie der Umgebungsvariablen auf Paragraphen-
  2600. ;    Grenze adjustiert sein.
  2601. ;<
  2602.     IF    ptrsize
  2603.     mov    ax,word ptr (envp)+2
  2604.     mov    bx,word ptr (envp)
  2605.     ELSE
  2606.     mov    ax,ds
  2607.     mov    bx,envp
  2608.     ENDIF
  2609.     add    bx,15            ;e make sure it's paragraph aligned
  2610.                     ;d auf Paragraphengrenze bringen
  2611.     mov    cl,4
  2612.     shr    bx,cl            ;e and convert to segment addr
  2613.                     ;d in Segment-Adresse konvertieren
  2614.     add    ax,bx
  2615.     mov    es:expar.envseg,ax    ;e new environment segment
  2616.                     ;d Neues Umgebungs-Segment
  2617.     xor    cx,cx            ;e mark no copy
  2618.                     ;d Markieren daß keine Kopie nötig
  2619.     xor    bx,bx            ;e and no shrink
  2620.                     ;d und keine Speicherreduzierung
  2621.     jmp    short no_environ
  2622. ;>e
  2623. ;    Swapping or EXECing without return. Set up the pointers for
  2624. ;    an environment copy (we can't do the copy yet, it might overwrite
  2625. ;    this code).
  2626. ;<
  2627. ;>d
  2628. ;    Auslagerung, oder EXEC ohne Rückkehr. Die Zeiger für das
  2629. ;    kopieren der Umgebungsvariablen aufsetzen. Der Block darf
  2630. ;    jetzt noch nicht kopiert werden, da dies eventuell den gerade
  2631. ;    ausgeführten Code überschreiben könnte.
  2632. ;<
  2633. do_envcopy:
  2634.     inc    cx
  2635.     shr    cx,1            ;e words to copy
  2636.                     ;d Zu kopierende Worte
  2637.     mov    ax,cx            ;e convert envsize to paras
  2638.                     ;d in Paragraphen konvertieren
  2639.     add    ax,7
  2640.     shr    ax,1
  2641.     shr    ax,1
  2642.     shr    ax,1
  2643.     add    bx,ax            ;e add envsize to paras to keep
  2644.                     ;d Größe zu residenter addieren
  2645.     IF    ptrsize
  2646.     lds    si,envp
  2647.     ELSE
  2648.     mov    si,envp
  2649.     ENDIF
  2650. ;
  2651.     mov    ax,es            ;e low core segment
  2652.                     ;d Segmentadresse residenter Teil
  2653.     add    ax,keep_paras        ;e plus fixed paras
  2654.                     ;d plus residente Paragraphen
  2655.     mov    es:expar.envseg,ax    ;e = new environment segment
  2656.                     ;d = neues Umgebungs-Segment
  2657. ;
  2658. ;e    Save stack regs, switch to local stack
  2659. ;d    Sichern Stack-Register, Umschalten auf lokalen Stack
  2660. ;
  2661. no_environ:
  2662.     mov    es:save_ss,ss
  2663.     mov    es:save_sp,sp
  2664.     mov    ax,es
  2665.     mov    ss,ax
  2666.     mov    sp,mystack
  2667. ;
  2668.     push    cx            ; save env length
  2669.     push    si            ; save env pointer
  2670.     push    ds            ; save env segment
  2671. ;
  2672. ;e    save and patch INT0 (division by zero) vector
  2673. ;d    Sichern und überschreiben INT0 (division by zero) Vektor
  2674. ;
  2675.     xor    ax,ax
  2676.     mov    ds,ax
  2677.     mov    ax,word ptr ds:0
  2678.     mov    es:div0_off,ax
  2679.     mov    ax,word ptr ds:2
  2680.     mov    es:div0_seg,ax
  2681.     mov    word ptr ds:0,codebeg + iretoff
  2682.     mov    word ptr ds:2,es
  2683. ;
  2684.     pop    ds            ; pop environment segment
  2685.     pop    si            ; pop environment offset
  2686.     pop    cx            ; pop environment length
  2687.     mov    di,swapbeg        ;e environment destination
  2688.                     ;d Zieladresse Umgebungsblock
  2689. ;
  2690. ;e    Push return address on local stack
  2691. ;d    Rückkehradresse auf lokalen Stack bringen
  2692. ;
  2693.     push    cs            ;e push return segment
  2694.                     ;d Rückkehr-Segment pushen
  2695.     mov    ax,offset exec_cont
  2696.     push    ax            ;e push return offset
  2697.                     ;d Rückkehr-Offset pushen
  2698.     mov    es:spx,sp        ;e save stack pointer
  2699.                     ;d Stack-Zeiger sichern
  2700. ;
  2701. ;e    Goto low core code
  2702. ;d    In den residenten Teil springen
  2703. ;
  2704.     push    es            ;e push entry segment
  2705.                     ;d Einsprungssegment pushen
  2706.         mov    ax,codebeg + doexec_entry
  2707.         push    ax            ;e push entry offset
  2708.                     ;d Einsprungsoffset pushen
  2709. ;e    ret    far            ; can't use RET here because
  2710. ;d    ret    far            ; RET kann hier wegen der .model-
  2711.     db    0cbh            ;e of .model
  2712.                     ;d Direktive nicht verwendet werden
  2713. ;
  2714. ;----------------------------------------------------------------
  2715. ;>e
  2716. ;    Low core code will return to this location, with DS set to
  2717. ;    the PSP segment.
  2718. ;<
  2719. ;>d
  2720. ;    Der residente Teil kehrt hierher zurück, mit DS = PSP-Segment.
  2721. ;<
  2722. exec_cont:
  2723.     push    ds
  2724.     pop    es
  2725.     mov    ss,ds:save_ss        ;e reload stack
  2726.                     ;d Stack zurückladen
  2727.     mov    sp,ds:save_sp
  2728. ;
  2729. ;e    restore INT0 (division by zero) vector
  2730. ;d    INT0 (division by zero) Vektor wiederherstellen
  2731. ;
  2732.     xor    cx,cx
  2733.     mov    ds,cx
  2734.     mov    cx,es:div0_off
  2735.     mov    word ptr ds:0,cx
  2736.     mov    cx,es:div0_seg
  2737.     mov    word ptr ds:2,cx
  2738. ;
  2739.     mov    ax,es:eretcode
  2740.     mov    bx,es:retflags
  2741.     mov    ds,datseg
  2742. ;
  2743. ;e    Restore overwritten part of program
  2744. ;d    Den überschriebenen Teil des Programms wiederherstellen
  2745. ;
  2746.     mov    si,offset save_dat
  2747.     mov    di,5ch
  2748.     mov    cx,savespace
  2749.     rep movsb
  2750. ;
  2751.     test    bx,1            ;e carry set?
  2752.                     ;d Carry-Flag gesetzt?
  2753.     jnz    exec_fault        ;e return EXEC error code if fault
  2754.                     ;d EXEC Fehler-code liefern wenn ja
  2755.     mov    ah,4dh            ;e else get program return code
  2756.                     ;d Sonst Programm-Rückgabewert holen
  2757.     int    21h
  2758.     ret
  2759. ;
  2760. exec_fault:
  2761.     mov    ah,3            ;e return error as 03xx
  2762.                     ;d EXEC-Fehler als 03xx liefern
  2763.     ret
  2764. ;    
  2765. do_spawn    ENDP
  2766. ;
  2767. ;----------------------------------------------------------------------------
  2768. ;----------------------------------------------------------------------------
  2769. ;
  2770. emm_name    db    'EMMXXXX0'
  2771. ;>e
  2772. ;    prep_swap - prepare for swapping.
  2773. ;
  2774. ;    This routine checks all parameters necessary for swapping,
  2775. ;    and attempts to set up the swap-out area in EMS/XMS, or on file.
  2776. ;    In detail:
  2777. ;
  2778. ;         1) Check whether the do_spawn routine is located
  2779. ;        too low in memory, so it would get overwritten.
  2780. ;        If this is true, return an error code (-2).
  2781. ;
  2782. ;         2) Walk the memory control block chain, adding up the
  2783. ;        paragraphs in all blocks assigned to this process.
  2784. ;
  2785. ;         3) Check EMS (if the method parameter allows EMS):
  2786. ;        - is an EMS driver installed?
  2787. ;        - are sufficient EMS pages available?
  2788. ;        if all goes well, the EMS pages are allocated, and the
  2789. ;        routine returns success (1).
  2790. ;
  2791. ;         4) Check XMS (if the method parameter allows XMS):
  2792. ;        - is an XMS driver installed?
  2793. ;        - is a sufficient XMS block available?
  2794. ;        if all goes well, the XMS block is allocated, and the
  2795. ;        routine returns success (2).
  2796. ;
  2797. ;         5) Check file swap (if the method parameter allows it):
  2798. ;        - try to create the file
  2799. ;        - pre-allocate the file space needed by seeking to the end
  2800. ;          and writing a byte.
  2801. ;        If the file can be written, the routine returns success (4).
  2802. ;
  2803. ;         6) Return an error code (-1).
  2804. ;<
  2805. ;>d
  2806. ;    prep_swap - Auslagerung vorbereiten.
  2807. ;
  2808. ;    Diese Routine prüft die zur Auslagerung nötigen Parameter,
  2809. ;    und versucht den Auslagerungsbereich in EMS, XMS, oder auf Datei,
  2810. ;    vorzubereiten.
  2811. ;    Im einzelnen:
  2812. ;
  2813. ;         1) Prüfen ob die do_spawn-Routine so niedrig liegt daß
  2814. ;        sie durch die Auslagerung überschrieben würde.
  2815. ;        Ist dies der Fall, Fehler (-2) liefern.
  2816. ;
  2817. ;         2) Die MCB-Kette durchlaufen, dabei die Länge in Paragraphen
  2818. ;        aller Blöcke addieren die zu diesem Prozeß gehören.
  2819. ;
  2820. ;         3) EMS prüfen (wenn der method Parameter EMS erlaubt):
  2821. ;        - ist ein EMS Treiber installiert?
  2822. ;        - sind genügend EMS-Seiten verfügbar?
  2823. ;        Wenn dies erfüllt ist, werden die EMS-Seiten alloziert,
  2824. ;        und die Routine liefert einen Erfolgscode (1).
  2825. ;
  2826. ;         4) XMS prüfen (wenn der method Parameter XMS erlaubt):
  2827. ;        - ist ein XMS Treiber installiert?
  2828. ;        - ist ein ausreichend großer XMS-Bereich verfügbar?
  2829. ;        Wenn dies erfüllt ist, wird der XMS-Bereich alloziert,
  2830. ;        und die Routine liefert einen Erfolgscode (2).
  2831. ;
  2832. ;         5) Dateiauslagerung prüfen (wenn der method Parameter es erlaubt):
  2833. ;        - die Datei erzeugen,
  2834. ;        - den benötigten Platz auf Datei prä-allozieren indem
  2835. ;          an das Ende positioniert und ein Byte geschrieben wird.
  2836. ;        Konnte die Datei geschrieben werden, liefert die Routine
  2837. ;        einen Erfolgscode (4).
  2838. ;
  2839. ;         6) Fehlercode liefern (-1).
  2840. ;<
  2841.     IFDEF    PASCAL
  2842.     IFDEF    FARCALL
  2843. prep_swap    PROC    far pmethod: word, swapfname: dword
  2844.     ELSE
  2845. prep_swap    PROC    near pmethod: word, swapfname: dword
  2846.     ENDIF
  2847.     ELSE
  2848. prep_swap    PROC    uses si di,pmethod:word,swapfname:ptr byte
  2849.     ENDIF
  2850.     LOCAL    totparas: word
  2851. ;
  2852.     IFDEF    TC_HUGE
  2853.     mov    ax,SEG my_data
  2854.     mov    ds,ax
  2855.     ENDIF
  2856. ;
  2857.     IFDEF    PASCAL
  2858.     cld
  2859.     mov    ax,prefixseg
  2860.     ELSE
  2861.     IFDEF    TC_HUGE
  2862.     mov    ax,SEG _psp
  2863.     mov    es,ax
  2864.     mov    ax,es:_psp
  2865.     ELSE
  2866.     mov    ax,_psp
  2867.     ENDIF
  2868.     ENDIF
  2869. ;
  2870.     dec    ax
  2871.     mov    prep.psp_mcb,ax
  2872.     mov    prep.first_mcb,ax    ;e init first MCB to PSP
  2873.                     ;d ersten MCB auf PSP initialisieren
  2874. ;
  2875. ;e    Make a copy of the environment pointer in the PSP
  2876. ;d    Eine Kopie vom Umgebungsvariablenblock-Pointer des PSP sichern
  2877. ;
  2878.     inc    ax
  2879.     mov    es,ax
  2880.     mov    bx,es:psp_envptr
  2881.     dec    bx
  2882.     mov    prep.env_mcb,bx
  2883.     mov    prep.noswap_mcb,0
  2884.     test    pmethod,DONT_SWAP_ENV
  2885.     jz    can_swap_env
  2886.     mov    prep.noswap_mcb,bx
  2887. ;
  2888. ;e    Check if spawn is too low in memory
  2889. ;d    Prüfen ob dieses Modul zu weit unten im Speicher liegt
  2890. ;
  2891. can_swap_env:
  2892.     mov    bx,cs
  2893.     mov    dx,offset lowcode_begin
  2894.     mov    cl,4
  2895.     shr    dx,cl
  2896.     add    bx,dx            ;e normalized start of this code
  2897.                     ;d Normalisierter Beginn des Codes
  2898.     mov    dx,keep_paras        ;e the end of the modified area
  2899.                     ;d Ende des modifizierten Bereichs
  2900.     add    dx,ax            ;e plus PSP = end paragraph
  2901.                     ;d plus PSP = letzer Paragraph
  2902.     cmp    bx,dx
  2903.     ja    prepswap_ok    ;e ok if start of code > end of low mem
  2904.                 ;d OK wenn Code-Beginn > Ende residenter Teil
  2905.     mov    ax,-2
  2906.     mov    prep.swapmethod,al
  2907.     ret
  2908. ;>e
  2909. ;    Walk the chain of memory blocks, adding up the paragraphs
  2910. ;    in all blocks belonging to this process.
  2911. ;    We try to find the first MCB by getting DOS's "list of lists",
  2912. ;    and fetching the word at offset -2 of the returned address.
  2913. ;    If this fails, we use our PSP as the starting point.
  2914. ;<
  2915. ;>d
  2916. ;    Die Speicherblöcke durchgehen und die Größe aller zu diesem
  2917. ;    Prozeß gehörenden Blöcke zusammenzählen.
  2918. ;    Der Anfang der MCB-Liste wird aus der DOS "list of lists"
  2919. ;    abgeleitet. Das Wort an Offset -2 der gelieferten Adresse
  2920. ;    enthält die erste MCB-Adresse. Falls dies fehlschlägt, wird
  2921. ;    der PSP als Ausgangspunkt benutzt.
  2922. ;<
  2923. prepswap_ok:
  2924.     xor    bx,bx
  2925.     mov    es,bx
  2926.     mov    ah,52h            ; get list of lists
  2927.     int    21h
  2928.     mov    ax,es
  2929.     or    ax,bx
  2930.     jz    prep_no_first
  2931.     mov    es,es:[bx-2]        ; first MCB
  2932.     cmp    es:id,4dh        ; normal ID?
  2933.     jne    prep_no_first
  2934.     mov    prep.first_mcb,es
  2935. ;
  2936. prep_no_first:
  2937.     mov    es,prep.psp_mcb        ;e ES points to base MCB
  2938.                     ;d ES zeigt auf Basis-Block
  2939.     mov    cx,es            ;e save this value
  2940.                     ;d diesen Wert sichern
  2941.     mov    bx,es:owner        ;e the current process
  2942.                     ;d Der aktuelle Prozeß
  2943.     mov    dx,es:paras        ;e memory size in the base block
  2944.                     ;d Speichergröße des Basisblocks
  2945.     sub    dx,keep_paras        ;e minus resident paragraphs
  2946.                     ;d Abzüglich residente Paragraphen
  2947.     mov    si,0            ;e number of MCBs except base
  2948.                     ;d Zähler für MCBs außer Basis
  2949.     mov    di,prep.noswap_mcb
  2950.     mov    ax,prep.first_mcb
  2951.     mov    prep.first_mcb,0
  2952. ;
  2953. prep_mcb_walk:
  2954.     mov    es,ax
  2955.     cmp    ax,cx            ;e base block?
  2956.                     ;d Basisblock?
  2957.     je    prep_walk_next        ;e then don't count again
  2958.                     ;d dann nicht nochmal zählen
  2959.     cmp    ax,di            ;e Non-swap MCB?
  2960.     je    prep_walk_next        ;e then don't count
  2961.                     ;d dann nicht zählen
  2962. ;
  2963.     cmp    bx,es:owner        ;e our process?
  2964.                     ;d aktueller Prozeß?
  2965.     jne    prep_walk_next        ;e next if not
  2966.                     ;d nächsten wenn nein
  2967.     inc    si
  2968.     mov    ax,es:paras        ;e else get number of paragraphs
  2969.                     ;d sonst Größe in Paragraphen laden
  2970.     add    ax,2            ; + 1 for descriptor + 1 for MCB
  2971.     add    dx,ax            ;e total number of paras
  2972.                     ;d Gesamtzahl Paragraphen
  2973.     cmp    prep.first_mcb,0
  2974.     jne    prep_walk_next
  2975.     mov    prep.first_mcb,es
  2976. ;
  2977. prep_walk_next:
  2978.     cmp    es:id,4dh        ;e normal block?
  2979.                     ;d normaler Block?
  2980.     jne    prep_mcb_ready        ;e ready if end of chain
  2981.                     ;d Fertig wenn ende der Kette
  2982.     mov    ax,es
  2983.     add    ax,es:paras        ; start + length
  2984.     inc    ax            ; next MCB
  2985.     jmp    prep_mcb_walk
  2986. ;
  2987. prep_mcb_ready:
  2988.     mov    totparas,dx
  2989.     mov    prep.total_mcbs,si
  2990. ;
  2991.     test    pmethod,XMS_FIRST
  2992.     jnz    check_xms
  2993. ;
  2994. ;e    Check for EMS swap
  2995. ;d    EMS-auslagerung prüfen
  2996. ;
  2997. check_ems:
  2998.     test    pmethod,USE_EMS
  2999.     jz    prep_no_ems
  3000. ;
  3001.     push    ds
  3002.     mov    al,EMM_INT
  3003.     mov    ah,35h
  3004.     int    21h            ;e get EMM int vector
  3005.                     ;d EMM-Interrupt Vektor laden
  3006.     mov    ax,cs
  3007.     mov    ds,ax
  3008.     mov    si,offset emm_name
  3009.     mov    di,10
  3010.     mov    cx,8
  3011.     repz cmpsb            ;e EMM name present?
  3012.                     ;d ist der EMM-Name vorhanden?
  3013.     pop    ds
  3014.     jnz    prep_no_ems
  3015. ;
  3016.     mov    ah,40h            ;e get EMS status
  3017.                     ;d EMS-Status abfragen
  3018.     int    EMM_INT
  3019.     or    ah,ah            ; EMS ok?
  3020.     jnz    prep_no_ems
  3021. ;
  3022.     mov    ah,46h            ;e get EMS version
  3023.                     ;d EMS-Version abfragen
  3024.     int    EMM_INT
  3025.     or    ah,ah            ; AH must be 0
  3026.     jnz    prep_no_ems
  3027. ;
  3028.     cmp    al,30h            ; >= version 3.0?
  3029.     jb    prep_no_ems
  3030. ;
  3031.     mov    ah,41h            ;e Get page frame address
  3032.                     ;d EMS-Frame-Adresse holen
  3033.     int    EMM_INT
  3034.     or    ah,ah
  3035.     jnz    prep_no_ems
  3036. ;
  3037. ;e    EMS present, try to allocate pages
  3038. ;d    EMS vorhanden, versuche Seiten zu allozieren
  3039. ;
  3040.     mov    prep.ems_pageframe,bx
  3041.     mov    bx,totparas
  3042.     add    bx,ems_paramask
  3043.     mov    cl,ems_shift
  3044.     shr    bx,cl
  3045.     mov    ah,43h            ; allocate handle and pages
  3046.     int    EMM_INT
  3047.     or    ah,ah            ;e success?
  3048.                     ;d erfolgreich?
  3049.     jnz    prep_no_ems
  3050. ;
  3051. ;e    EMS pages allocated, swap to EMS
  3052. ;d    EMS-Seiten alloziert, auslagern auf EMS
  3053. ;
  3054.     mov    prep.handle,dx
  3055.     mov    ax,USE_EMS
  3056.     mov    prep.swapmethod,al
  3057.     ret
  3058. ;
  3059. ;e    No EMS allowed, or EMS not present/full. Try XMS.
  3060. ;d    EMS nicht erlaubt, oder EMS nicht vorhanden/voll. XMS versuchen.
  3061. ;
  3062. prep_no_ems:
  3063.     test    pmethod,XMS_FIRST
  3064.     jnz    check_file        ;e don't try again
  3065.                     ;d nicht nochmal versuchen
  3066. ;
  3067. check_xms:
  3068.     test    pmethod,USE_XMS
  3069.     jz    prep_no_xms
  3070. ;
  3071.     mov    ax,4300h        ;e check if XMM driver present
  3072.                     ;d prüfen ob XMM-Treiber vorhanden
  3073.     int    2fh
  3074.     cmp    al,80h            ;e is XMM installed?
  3075.                     ;d ist XMM installiert?
  3076.     jne    prep_no_xms
  3077.     mov    ax,4310h        ;e get XMM entrypoint
  3078.                     ;d XMM-Einsprungadresse holen
  3079.     int    2fh
  3080.     mov    word ptr prep.xmm,bx    ;e save entry address
  3081.                     ;d Einsprungadresse sichern
  3082.     mov    word ptr prep.xmm+2,es
  3083. ;
  3084.     mov    dx,totparas
  3085.     add    dx,xms_paramask        ;e round to nearest multiple of 1k
  3086.                     ;d Auf volle 1k aufrunden
  3087.     mov    cl,xms_shift
  3088.     shr    dx,cl            ;e convert to k
  3089.                     ;d konvertiern in k
  3090.     mov    ah,9            ;e allocate extended memory block
  3091.                     ;d Extended memory block allozieren
  3092.     call    prep.xmm
  3093.     or    ax,ax
  3094.     jz    prep_no_xms
  3095. ;
  3096. ;e    XMS block allocated, swap to XMS
  3097. ;d    XMS-Block alloziert, Auslagern auf XMS.
  3098. ;
  3099.     mov    prep.handle,dx
  3100.     mov    ax,USE_XMS
  3101.     mov    prep.swapmethod,al
  3102.     ret
  3103. ;
  3104. ;e    No XMS allowed, or XMS not present/full. Try File swap.
  3105. ;d    XMS nicht erlaubt, oder XMS nicht vorhanden/voll. Datei versuchen.
  3106. ;
  3107. prep_no_xms:
  3108.     test    pmethod,XMS_FIRST
  3109.     jz    check_file
  3110.     jmp    check_ems
  3111. ;
  3112. check_file:
  3113.     test    pmethod,USE_FILE
  3114.     jnz    prep_do_file
  3115.     jmp    prep_no_file
  3116. ;
  3117. prep_do_file:
  3118.     push    ds
  3119.     IF    ptrsize
  3120.     lds    dx,swapfname
  3121.     ELSE
  3122.     mov    dx,swapfname
  3123.     ENDIF
  3124.     IFDEF    PASCAL
  3125.     inc    dx            ;e skip length byte
  3126.                     ;d Längenbyte überspringen
  3127.     ENDIF
  3128.     mov    cx,2            ; hidden attribute
  3129.     test    pmethod,HIDE_FILE
  3130.     jnz    prep_hide
  3131.     xor    cx,cx            ; normal attribute
  3132. ;
  3133. prep_hide:
  3134.     mov    ah,3ch            ; create file
  3135.     test    pmethod,CREAT_TEMP
  3136.     jz    prep_no_temp
  3137.     mov    ah,5ah
  3138. ;
  3139. prep_no_temp:
  3140.     int    21h            ; create/create temp
  3141.     jnc    prep_got_file
  3142.     jmp    prep_no_file
  3143. ;
  3144. prep_got_file:
  3145.     mov    bx,ax            ; handle
  3146. ;
  3147. ;e    save the file name
  3148. ;d    Dateinamen sichern
  3149. ;
  3150.     pop    es
  3151.     push    es
  3152.     mov    di,offset prep.swapfilename
  3153.     mov    cx,81
  3154.     mov    si,dx
  3155.     rep movsb
  3156. ;
  3157.     pop    ds
  3158.     mov    prep.handle,bx
  3159. ;
  3160. ;e    preallocate the file
  3161. ;d    Datei-Speicherplatz prä-allozieren
  3162. ;
  3163.     test    pmethod,NO_PREALLOC
  3164.     jnz    prep_noprealloc
  3165.     test    pmethod,CHECK_NET
  3166.     jz    prep_nonetcheck
  3167. ;
  3168. ;e    check whether file is on a network drive, and don't preallocate
  3169. ;e    if so. preallocation can slow down swapping significantly when
  3170. ;e    running on certain networks (Novell)
  3171. ;d    Prüfen ob Datei auf einem Netwerk-Laufwerk liegt, und nicht
  3172. ;d    präallozieren wenn ja. Ein Präallozieren kann den Swap-Vorgang
  3173. ;d    erheblich verlangsamen wenn es auf Novell-Drives ausgeführt wird.
  3174. ;
  3175.     mov    ax,440ah    ; check if handle is remote
  3176.     int    21h
  3177.     jc    prep_nonetcheck    ;e assume not remote if function fails
  3178.                 ;d kein Netz wenn Funktion Fehler liefert
  3179.     test    dh,80h        ;e DX bit 15 set ?
  3180.                 ;d Ist Bit 15 von DX gesetzt?
  3181.     jnz    prep_noprealloc    ;e remote if yes
  3182.                 ;d Netzwerk-Datei wenn ja
  3183. ;
  3184. prep_nonetcheck:
  3185.     mov    dx,totparas
  3186.     mov    cl,4
  3187.     rol    dx,cl
  3188.     mov    cx,dx
  3189.     and    dx,0fff0h
  3190.     and    cx,0000fh
  3191.     sub    dx,1
  3192.     sbb    cx,0
  3193.     mov    si,dx            ; save
  3194.     mov    ax,4200h        ; move file pointer, absolute
  3195.     int    21h
  3196.     jc    prep_file_err
  3197.     cmp    dx,cx
  3198.     jne    prep_file_err
  3199.     cmp    ax,si
  3200.     jne    prep_file_err
  3201.     mov    cx,1            ;e write 1 byte
  3202.                     ;d 1 Byte schreiben
  3203.     mov    ah,40h
  3204.     int    21h
  3205.     jc    prep_file_err
  3206.     cmp    ax,cx
  3207.     jne    prep_file_err
  3208. ;
  3209.     mov    ax,4200h        ; move file pointer, absolute
  3210.     xor    dx,dx
  3211.     xor    cx,cx            ;e rewind to beginning
  3212.                     ;d Auf Anfang zurückpositionieren
  3213.     int    21h
  3214.     jc    prep_file_err
  3215. ;
  3216. prep_noprealloc:
  3217.     mov    ax,USE_FILE
  3218.     mov    prep.swapmethod,al
  3219.     ret
  3220. ;
  3221. prep_file_err:
  3222.     mov    ah,3eh            ; close file
  3223.     int    21h
  3224.     mov    dx,offset prep.swapfilename
  3225.     mov    ah,41h            ; delete file
  3226.     int    21h
  3227. ;
  3228. prep_no_file:
  3229.     mov    ax,-1
  3230.     mov    prep.swapmethod,al
  3231.     ret
  3232. ;
  3233. prep_swap    endp
  3234. ;
  3235.     end
  3236.  
  3237.